feat: Add endpoints for activity statistics and uncategorized activities
- Implemented a new endpoint to retrieve activity statistics for the last 30 entries, including total calories and duration by activity type. - Added an endpoint to list activities without assigned training types, grouped by activity type. - Removed deprecated versions of the statistics and uncategorized activities endpoints for cleaner code.
This commit is contained in:
parent
196b6c5cf1
commit
db9952525a
|
|
@ -133,6 +133,66 @@ def create_activity(e: ActivityEntry, x_profile_id: Optional[str]=Header(default
|
||||||
return {"id":eid,"date":e.date}
|
return {"id":eid,"date":e.date}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/stats")
|
||||||
|
def activity_stats(session: dict = Depends(require_auth)):
|
||||||
|
"""Get activity statistics (last 30 entries)."""
|
||||||
|
pid = str(session["profile_id"])
|
||||||
|
with get_db() as conn:
|
||||||
|
cur = get_cursor(conn)
|
||||||
|
cur.execute("SELECT * FROM profiles WHERE id=%s", (pid,))
|
||||||
|
profile = r2d(cur.fetchone())
|
||||||
|
quality_filter = get_quality_filter_sql(profile or {})
|
||||||
|
cur.execute(
|
||||||
|
f"""
|
||||||
|
SELECT * FROM activity_log
|
||||||
|
WHERE profile_id=%s {quality_filter}
|
||||||
|
ORDER BY date DESC
|
||||||
|
LIMIT 30
|
||||||
|
""",
|
||||||
|
(pid,),
|
||||||
|
)
|
||||||
|
rows = [r2d(r) for r in cur.fetchall()]
|
||||||
|
if not rows:
|
||||||
|
return {"count": 0, "total_kcal": 0, "total_min": 0, "by_type": {}}
|
||||||
|
total_kcal = sum(float(r.get("kcal_active") or 0) for r in rows)
|
||||||
|
total_min = sum(float(r.get("duration_min") or 0) for r in rows)
|
||||||
|
by_type = {}
|
||||||
|
for r in rows:
|
||||||
|
t = r["activity_type"]
|
||||||
|
by_type.setdefault(t, {"count": 0, "kcal": 0, "min": 0})
|
||||||
|
by_type[t]["count"] += 1
|
||||||
|
by_type[t]["kcal"] += float(r.get("kcal_active") or 0)
|
||||||
|
by_type[t]["min"] += float(r.get("duration_min") or 0)
|
||||||
|
return {
|
||||||
|
"count": len(rows),
|
||||||
|
"total_kcal": round(total_kcal),
|
||||||
|
"total_min": round(total_min),
|
||||||
|
"by_type": by_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/uncategorized")
|
||||||
|
def list_uncategorized_activities(
|
||||||
|
session: dict = Depends(require_auth),
|
||||||
|
):
|
||||||
|
"""Get activities without assigned training type, grouped by activity_type."""
|
||||||
|
pid = str(session["profile_id"])
|
||||||
|
with get_db() as conn:
|
||||||
|
cur = get_cursor(conn)
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT activity_type, COUNT(*) as count,
|
||||||
|
MIN(date) as first_date, MAX(date) as last_date
|
||||||
|
FROM activity_log
|
||||||
|
WHERE profile_id=%s AND training_type_id IS NULL
|
||||||
|
GROUP BY activity_type
|
||||||
|
ORDER BY count DESC
|
||||||
|
""",
|
||||||
|
(pid,),
|
||||||
|
)
|
||||||
|
return [r2d(r) for r in cur.fetchall()]
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{eid}")
|
@router.put("/{eid}")
|
||||||
def update_activity(eid: str, e: ActivityEntry, x_profile_id: Optional[str]=Header(default=None), session: dict=Depends(require_auth)):
|
def update_activity(eid: str, e: ActivityEntry, x_profile_id: Optional[str]=Header(default=None), session: dict=Depends(require_auth)):
|
||||||
"""Update existing activity entry."""
|
"""Update existing activity entry."""
|
||||||
|
|
@ -228,37 +288,6 @@ def get_activity_session(
|
||||||
return unit
|
return unit
|
||||||
|
|
||||||
|
|
||||||
@router.get("/stats")
|
|
||||||
def activity_stats(session: dict = Depends(require_auth)):
|
|
||||||
"""Get activity statistics (last 30 entries)."""
|
|
||||||
pid = str(session["profile_id"])
|
|
||||||
with get_db() as conn:
|
|
||||||
cur = get_cursor(conn)
|
|
||||||
cur.execute("SELECT * FROM profiles WHERE id=%s", (pid,))
|
|
||||||
profile = r2d(cur.fetchone())
|
|
||||||
quality_filter = get_quality_filter_sql(profile or {})
|
|
||||||
cur.execute(
|
|
||||||
f"""
|
|
||||||
SELECT * FROM activity_log
|
|
||||||
WHERE profile_id=%s {quality_filter}
|
|
||||||
ORDER BY date DESC
|
|
||||||
LIMIT 30
|
|
||||||
""",
|
|
||||||
(pid,),
|
|
||||||
)
|
|
||||||
rows = [r2d(r) for r in cur.fetchall()]
|
|
||||||
if not rows: return {"count":0,"total_kcal":0,"total_min":0,"by_type":{}}
|
|
||||||
total_kcal=sum(float(r.get('kcal_active') or 0) for r in rows)
|
|
||||||
total_min=sum(float(r.get('duration_min') or 0) for r in rows)
|
|
||||||
by_type={}
|
|
||||||
for r in rows:
|
|
||||||
t=r['activity_type']; by_type.setdefault(t,{'count':0,'kcal':0,'min':0})
|
|
||||||
by_type[t]['count']+=1
|
|
||||||
by_type[t]['kcal']+=float(r.get('kcal_active') or 0)
|
|
||||||
by_type[t]['min']+=float(r.get('duration_min') or 0)
|
|
||||||
return {"count":len(rows),"total_kcal":round(total_kcal),"total_min":round(total_min),"by_type":by_type}
|
|
||||||
|
|
||||||
|
|
||||||
def get_training_type_for_activity_with_cursor(cur, activity_type: str, profile_id: str | None = None):
|
def get_training_type_for_activity_with_cursor(cur, activity_type: str, profile_id: str | None = None):
|
||||||
"""
|
"""
|
||||||
Wie get_training_type_for_activity, aber mit bestehendem Cursor (z. B. Universal-CSV-Import).
|
Wie get_training_type_for_activity, aber mit bestehendem Cursor (z. B. Universal-CSV-Import).
|
||||||
|
|
@ -312,23 +341,6 @@ def get_training_type_for_activity(activity_type: str, profile_id: str = None):
|
||||||
return get_training_type_for_activity_with_cursor(cur, activity_type, profile_id)
|
return get_training_type_for_activity_with_cursor(cur, activity_type, profile_id)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/uncategorized")
|
|
||||||
def list_uncategorized_activities(x_profile_id: Optional[str]=Header(default=None), session: dict=Depends(require_auth)):
|
|
||||||
"""Get activities without assigned training type, grouped by activity_type."""
|
|
||||||
pid = get_pid(x_profile_id)
|
|
||||||
with get_db() as conn:
|
|
||||||
cur = get_cursor(conn)
|
|
||||||
cur.execute("""
|
|
||||||
SELECT activity_type, COUNT(*) as count,
|
|
||||||
MIN(date) as first_date, MAX(date) as last_date
|
|
||||||
FROM activity_log
|
|
||||||
WHERE profile_id=%s AND training_type_id IS NULL
|
|
||||||
GROUP BY activity_type
|
|
||||||
ORDER BY count DESC
|
|
||||||
""", (pid,))
|
|
||||||
return [r2d(r) for r in cur.fetchall()]
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/bulk-categorize")
|
@router.post("/bulk-categorize")
|
||||||
def bulk_categorize_activities(
|
def bulk_categorize_activities(
|
||||||
data: dict,
|
data: dict,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user