UI fixes
This commit is contained in:
@@ -4,7 +4,7 @@ Medications API - medication scheduling, logging, and adherence tracking
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime, date, timedelta
|
||||
from datetime import datetime, date, timedelta, timezone
|
||||
|
||||
import flask
|
||||
import jwt
|
||||
@@ -109,12 +109,25 @@ def _count_expected_doses(med, period_start, days):
|
||||
return days * times_per_day
|
||||
|
||||
|
||||
def _count_logs_in_period(logs, period_start_str, action):
|
||||
"""Count logs of a given action where created_at >= period_start."""
|
||||
def _log_local_date(created_at, user_tz):
|
||||
"""Convert a DB created_at (naive UTC datetime) to a local date string YYYY-MM-DD."""
|
||||
if created_at is None:
|
||||
return ""
|
||||
if isinstance(created_at, datetime):
|
||||
# Treat naive datetimes as UTC
|
||||
if created_at.tzinfo is None:
|
||||
created_at = created_at.replace(tzinfo=timezone.utc)
|
||||
return created_at.astimezone(user_tz).date().isoformat()
|
||||
# Fallback: already a string
|
||||
return str(created_at)[:10]
|
||||
|
||||
|
||||
def _count_logs_in_period(logs, period_start_str, action, user_tz=None):
|
||||
"""Count logs of a given action where created_at (local date) >= period_start."""
|
||||
return sum(
|
||||
1 for log in logs
|
||||
if log.get("action") == action
|
||||
and str(log.get("created_at", ""))[:10] >= period_start_str
|
||||
and (_log_local_date(log.get("created_at"), user_tz) if user_tz else str(log.get("created_at", ""))[:10]) >= period_start_str
|
||||
)
|
||||
|
||||
|
||||
@@ -324,6 +337,7 @@ def register(app):
|
||||
|
||||
meds = postgres.select("medications", where={"user_uuid": user_uuid, "active": True})
|
||||
now = tz.user_now()
|
||||
user_tz = now.tzinfo
|
||||
today = now.date()
|
||||
today_str = today.isoformat()
|
||||
current_day = now.strftime("%a").lower() # "mon","tue", etc.
|
||||
@@ -345,16 +359,16 @@ def register(app):
|
||||
where={"medication_id": med["id"]},
|
||||
)
|
||||
today_taken = [
|
||||
log.get("scheduled_time", "")
|
||||
log.get("scheduled_time") or ""
|
||||
for log in all_logs
|
||||
if log.get("action") == "taken"
|
||||
and str(log.get("created_at", ""))[:10] == today_str
|
||||
and _log_local_date(log.get("created_at"), user_tz) == today_str
|
||||
]
|
||||
today_skipped = [
|
||||
log.get("scheduled_time", "")
|
||||
log.get("scheduled_time") or ""
|
||||
for log in all_logs
|
||||
if log.get("action") == "skipped"
|
||||
and str(log.get("created_at", ""))[:10] == today_str
|
||||
and _log_local_date(log.get("created_at"), user_tz) == today_str
|
||||
]
|
||||
|
||||
result.append({
|
||||
@@ -389,16 +403,16 @@ def register(app):
|
||||
where={"medication_id": med["id"]},
|
||||
)
|
||||
tomorrow_taken = [
|
||||
log.get("scheduled_time", "")
|
||||
log.get("scheduled_time") or ""
|
||||
for log in all_logs
|
||||
if log.get("action") == "taken"
|
||||
and str(log.get("created_at", ""))[:10] == tomorrow_str
|
||||
and _log_local_date(log.get("created_at"), user_tz) == tomorrow_str
|
||||
]
|
||||
tomorrow_skipped = [
|
||||
log.get("scheduled_time", "")
|
||||
log.get("scheduled_time") or ""
|
||||
for log in all_logs
|
||||
if log.get("action") == "skipped"
|
||||
and str(log.get("created_at", ""))[:10] == tomorrow_str
|
||||
and _log_local_date(log.get("created_at"), user_tz) == tomorrow_str
|
||||
]
|
||||
|
||||
result.append({
|
||||
@@ -434,16 +448,16 @@ def register(app):
|
||||
where={"medication_id": med["id"]},
|
||||
)
|
||||
yesterday_taken = [
|
||||
log.get("scheduled_time", "")
|
||||
log.get("scheduled_time") or ""
|
||||
for log in all_logs
|
||||
if log.get("action") == "taken"
|
||||
and str(log.get("created_at", ""))[:10] == yesterday_str
|
||||
and _log_local_date(log.get("created_at"), user_tz) == yesterday_str
|
||||
]
|
||||
yesterday_skipped = [
|
||||
log.get("scheduled_time", "")
|
||||
log.get("scheduled_time") or ""
|
||||
for log in all_logs
|
||||
if log.get("action") == "skipped"
|
||||
and str(log.get("created_at", ""))[:10] == yesterday_str
|
||||
and _log_local_date(log.get("created_at"), user_tz) == yesterday_str
|
||||
]
|
||||
|
||||
result.append({
|
||||
@@ -468,7 +482,9 @@ def register(app):
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
num_days = flask.request.args.get("days", 30, type=int)
|
||||
meds = postgres.select("medications", where={"user_uuid": user_uuid, "active": True})
|
||||
today = tz.user_today()
|
||||
now = tz.user_now()
|
||||
user_tz = now.tzinfo
|
||||
today = now.date()
|
||||
period_start = today - timedelta(days=num_days)
|
||||
period_start_str = period_start.isoformat()
|
||||
|
||||
@@ -479,8 +495,8 @@ def register(app):
|
||||
expected = _count_expected_doses(med, period_start, num_days)
|
||||
|
||||
logs = postgres.select("med_logs", where={"medication_id": med["id"]})
|
||||
taken = _count_logs_in_period(logs, period_start_str, "taken")
|
||||
skipped = _count_logs_in_period(logs, period_start_str, "skipped")
|
||||
taken = _count_logs_in_period(logs, period_start_str, "taken", user_tz)
|
||||
skipped = _count_logs_in_period(logs, period_start_str, "skipped", user_tz)
|
||||
|
||||
if is_prn:
|
||||
adherence_pct = None
|
||||
@@ -510,7 +526,9 @@ def register(app):
|
||||
if not med:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
num_days = flask.request.args.get("days", 30, type=int)
|
||||
today = tz.user_today()
|
||||
now = tz.user_now()
|
||||
user_tz = now.tzinfo
|
||||
today = now.date()
|
||||
period_start = today - timedelta(days=num_days)
|
||||
period_start_str = period_start.isoformat()
|
||||
|
||||
@@ -519,8 +537,8 @@ def register(app):
|
||||
expected = _count_expected_doses(med, period_start, num_days)
|
||||
|
||||
logs = postgres.select("med_logs", where={"medication_id": med_id})
|
||||
taken = _count_logs_in_period(logs, period_start_str, "taken")
|
||||
skipped = _count_logs_in_period(logs, period_start_str, "skipped")
|
||||
taken = _count_logs_in_period(logs, period_start_str, "taken", user_tz)
|
||||
skipped = _count_logs_in_period(logs, period_start_str, "skipped", user_tz)
|
||||
|
||||
if is_prn:
|
||||
adherence_pct = None
|
||||
|
||||
@@ -6,6 +6,7 @@ Routines have ordered steps. Users start sessions to walk through them.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import json
|
||||
from datetime import datetime
|
||||
import flask
|
||||
import jwt
|
||||
@@ -39,6 +40,7 @@ def _make_aware_utc(dt):
|
||||
"""Ensure a datetime is timezone-aware; assume naive datetimes are UTC."""
|
||||
if dt.tzinfo is None:
|
||||
from datetime import timezone as _tz
|
||||
|
||||
return dt.replace(tzinfo=_tz.utc)
|
||||
return dt
|
||||
|
||||
@@ -73,15 +75,18 @@ def _record_step_result(session_id, step_id, step_index, result, session):
|
||||
else:
|
||||
duration_seconds = None
|
||||
|
||||
postgres.insert("routine_step_results", {
|
||||
"id": str(uuid.uuid4()),
|
||||
"session_id": session_id,
|
||||
"step_id": step_id,
|
||||
"step_index": step_index,
|
||||
"result": result,
|
||||
"duration_seconds": duration_seconds,
|
||||
"completed_at": now.isoformat(),
|
||||
})
|
||||
postgres.insert(
|
||||
"routine_step_results",
|
||||
{
|
||||
"id": str(uuid.uuid4()),
|
||||
"session_id": session_id,
|
||||
"step_id": step_id,
|
||||
"step_index": step_index,
|
||||
"result": result,
|
||||
"duration_seconds": duration_seconds,
|
||||
"completed_at": now.isoformat(),
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
pass # Don't fail the step completion if tracking fails
|
||||
|
||||
@@ -99,11 +104,15 @@ def _complete_session_with_celebration(session_id, user_uuid, session):
|
||||
duration_minutes = 0
|
||||
|
||||
# Update session as completed with duration — this MUST succeed
|
||||
postgres.update("routine_sessions", {
|
||||
"status": "completed",
|
||||
"completed_at": now.isoformat(),
|
||||
"actual_duration_minutes": int(duration_minutes),
|
||||
}, {"id": session_id})
|
||||
postgres.update(
|
||||
"routine_sessions",
|
||||
{
|
||||
"status": "completed",
|
||||
"completed_at": now.isoformat(),
|
||||
"actual_duration_minutes": int(duration_minutes),
|
||||
},
|
||||
{"id": session_id},
|
||||
)
|
||||
|
||||
# Gather celebration stats — failures here should not break completion
|
||||
streak_current = 1
|
||||
@@ -115,10 +124,13 @@ def _complete_session_with_celebration(session_id, user_uuid, session):
|
||||
|
||||
try:
|
||||
streak_result = routines_core._update_streak(user_uuid, session["routine_id"])
|
||||
streak = postgres.select_one("routine_streaks", {
|
||||
"user_uuid": user_uuid,
|
||||
"routine_id": session["routine_id"],
|
||||
})
|
||||
streak = postgres.select_one(
|
||||
"routine_streaks",
|
||||
{
|
||||
"user_uuid": user_uuid,
|
||||
"routine_id": session["routine_id"],
|
||||
},
|
||||
)
|
||||
if streak:
|
||||
streak_current = streak["current_streak"]
|
||||
streak_longest = streak["longest_streak"]
|
||||
@@ -127,18 +139,23 @@ def _complete_session_with_celebration(session_id, user_uuid, session):
|
||||
pass
|
||||
|
||||
try:
|
||||
step_results = postgres.select("routine_step_results", {"session_id": session_id})
|
||||
step_results = postgres.select(
|
||||
"routine_step_results", {"session_id": session_id}
|
||||
)
|
||||
steps_completed = sum(1 for r in step_results if r.get("result") == "completed")
|
||||
steps_skipped = sum(1 for r in step_results if r.get("result") == "skipped")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
all_completed = postgres.select("routine_sessions", {
|
||||
"routine_id": session["routine_id"],
|
||||
"user_uuid": user_uuid,
|
||||
"status": "completed",
|
||||
})
|
||||
all_completed = postgres.select(
|
||||
"routine_sessions",
|
||||
{
|
||||
"routine_id": session["routine_id"],
|
||||
"user_uuid": user_uuid,
|
||||
"status": "completed",
|
||||
},
|
||||
)
|
||||
total_completions = len(all_completed)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -157,7 +174,6 @@ def _complete_session_with_celebration(session_id, user_uuid, session):
|
||||
|
||||
|
||||
def register(app):
|
||||
|
||||
# ── Routines CRUD ─────────────────────────────────────────────
|
||||
|
||||
@app.route("/api/routines", methods=["GET"])
|
||||
@@ -166,7 +182,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routines = postgres.select("routines", where={"user_uuid": user_uuid}, order_by="name")
|
||||
routines = postgres.select(
|
||||
"routines", where={"user_uuid": user_uuid}, order_by="name"
|
||||
)
|
||||
return flask.jsonify(routines), 200
|
||||
|
||||
@app.route("/api/routines", methods=["POST"])
|
||||
@@ -191,7 +209,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
steps = postgres.select(
|
||||
@@ -210,14 +230,25 @@ def register(app):
|
||||
data = flask.request.get_json()
|
||||
if not data:
|
||||
return flask.jsonify({"error": "missing body"}), 400
|
||||
existing = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
existing = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not existing:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
allowed = ["name", "description", "icon", "location", "environment_prompts", "habit_stack_after"]
|
||||
allowed = [
|
||||
"name",
|
||||
"description",
|
||||
"icon",
|
||||
"location",
|
||||
"environment_prompts",
|
||||
"habit_stack_after",
|
||||
]
|
||||
updates = {k: v for k, v in data.items() if k in allowed}
|
||||
if not updates:
|
||||
return flask.jsonify({"error": "no valid fields to update"}), 400
|
||||
result = postgres.update("routines", updates, {"id": routine_id, "user_uuid": user_uuid})
|
||||
result = postgres.update(
|
||||
"routines", updates, {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
return flask.jsonify(result[0] if result else {}), 200
|
||||
|
||||
@app.route("/api/routines/<routine_id>", methods=["DELETE"])
|
||||
@@ -226,7 +257,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
existing = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
existing = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not existing:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
postgres.delete("routine_sessions", {"routine_id": routine_id})
|
||||
@@ -243,7 +276,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
steps = postgres.select(
|
||||
@@ -259,7 +294,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
data = flask.request.get_json()
|
||||
@@ -290,20 +327,26 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
data = flask.request.get_json()
|
||||
if not data:
|
||||
return flask.jsonify({"error": "missing body"}), 400
|
||||
existing = postgres.select_one("routine_steps", {"id": step_id, "routine_id": routine_id})
|
||||
existing = postgres.select_one(
|
||||
"routine_steps", {"id": step_id, "routine_id": routine_id}
|
||||
)
|
||||
if not existing:
|
||||
return flask.jsonify({"error": "step not found"}), 404
|
||||
allowed = ["name", "duration_minutes", "position"]
|
||||
updates = {k: v for k, v in data.items() if k in allowed}
|
||||
if not updates:
|
||||
return flask.jsonify({"error": "no valid fields to update"}), 400
|
||||
result = postgres.update("routine_steps", updates, {"id": step_id, "routine_id": routine_id})
|
||||
result = postgres.update(
|
||||
"routine_steps", updates, {"id": step_id, "routine_id": routine_id}
|
||||
)
|
||||
return flask.jsonify(result[0] if result else {}), 200
|
||||
|
||||
@app.route("/api/routines/<routine_id>/steps/<step_id>", methods=["DELETE"])
|
||||
@@ -312,10 +355,14 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
existing = postgres.select_one("routine_steps", {"id": step_id, "routine_id": routine_id})
|
||||
existing = postgres.select_one(
|
||||
"routine_steps", {"id": step_id, "routine_id": routine_id}
|
||||
)
|
||||
if not existing:
|
||||
return flask.jsonify({"error": "step not found"}), 404
|
||||
postgres.delete("routine_steps", {"id": step_id, "routine_id": routine_id})
|
||||
@@ -327,7 +374,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
data = flask.request.get_json()
|
||||
@@ -335,7 +384,11 @@ def register(app):
|
||||
return flask.jsonify({"error": "missing step_ids"}), 400
|
||||
step_ids = data["step_ids"]
|
||||
for i, step_id in enumerate(step_ids):
|
||||
postgres.update("routine_steps", {"position": i + 1}, {"id": step_id, "routine_id": routine_id})
|
||||
postgres.update(
|
||||
"routine_steps",
|
||||
{"position": i + 1},
|
||||
{"id": step_id, "routine_id": routine_id},
|
||||
)
|
||||
steps = postgres.select(
|
||||
"routine_steps",
|
||||
where={"routine_id": routine_id},
|
||||
@@ -351,14 +404,22 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
active = postgres.select_one("routine_sessions", {"user_uuid": user_uuid, "status": "active"})
|
||||
active = postgres.select_one(
|
||||
"routine_sessions", {"user_uuid": user_uuid, "status": "active"}
|
||||
)
|
||||
if not active:
|
||||
active = postgres.select_one("routine_sessions", {"user_uuid": user_uuid, "status": "paused"})
|
||||
active = postgres.select_one(
|
||||
"routine_sessions", {"user_uuid": user_uuid, "status": "paused"}
|
||||
)
|
||||
if active:
|
||||
return flask.jsonify({"error": "already have active session", "session_id": active["id"]}), 409
|
||||
return flask.jsonify(
|
||||
{"error": "already have active session", "session_id": active["id"]}
|
||||
), 409
|
||||
steps = postgres.select(
|
||||
"routine_steps",
|
||||
where={"routine_id": routine_id},
|
||||
@@ -382,9 +443,13 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
session = postgres.select_one("routine_sessions", {"user_uuid": user_uuid, "status": "active"})
|
||||
session = postgres.select_one(
|
||||
"routine_sessions", {"user_uuid": user_uuid, "status": "active"}
|
||||
)
|
||||
if not session:
|
||||
session = postgres.select_one("routine_sessions", {"user_uuid": user_uuid, "status": "paused"})
|
||||
session = postgres.select_one(
|
||||
"routine_sessions", {"user_uuid": user_uuid, "status": "paused"}
|
||||
)
|
||||
if not session:
|
||||
return flask.jsonify({"error": "no active session"}), 404
|
||||
routine = postgres.select_one("routines", {"id": session["routine_id"]})
|
||||
@@ -393,8 +458,14 @@ def register(app):
|
||||
where={"routine_id": session["routine_id"]},
|
||||
order_by="position",
|
||||
)
|
||||
current_step = steps[session["current_step_index"]] if session["current_step_index"] < len(steps) else None
|
||||
return flask.jsonify({"session": session, "routine": routine, "current_step": current_step}), 200
|
||||
current_step = (
|
||||
steps[session["current_step_index"]]
|
||||
if session["current_step_index"] < len(steps)
|
||||
else None
|
||||
)
|
||||
return flask.jsonify(
|
||||
{"session": session, "routine": routine, "current_step": current_step}
|
||||
), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>/complete-step", methods=["POST"])
|
||||
def api_completeStep(session_id):
|
||||
@@ -402,14 +473,20 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
session = postgres.select_one("routine_sessions", {"id": session_id, "user_uuid": user_uuid})
|
||||
session = postgres.select_one(
|
||||
"routine_sessions", {"id": session_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not session:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
if session["status"] not in ("active", "paused"):
|
||||
return flask.jsonify({"error": "session not active"}), 400
|
||||
# Auto-resume if paused
|
||||
if session["status"] == "paused":
|
||||
postgres.update("routine_sessions", {"status": "active", "paused_at": None}, {"id": session_id})
|
||||
postgres.update(
|
||||
"routine_sessions",
|
||||
{"status": "active", "paused_at": None},
|
||||
{"id": session_id},
|
||||
)
|
||||
data = flask.request.get_json() or {}
|
||||
steps = postgres.select(
|
||||
"routine_steps",
|
||||
@@ -421,19 +498,32 @@ def register(app):
|
||||
|
||||
# Record step result
|
||||
if current_step:
|
||||
_record_step_result(session_id, current_step["id"], current_index, "completed", session)
|
||||
_record_step_result(
|
||||
session_id, current_step["id"], current_index, "completed", session
|
||||
)
|
||||
|
||||
next_index = current_index + 1
|
||||
if next_index >= len(steps):
|
||||
# Session complete — compute celebration data
|
||||
celebration = _complete_session_with_celebration(session_id, user_uuid, session)
|
||||
return flask.jsonify({
|
||||
"session": {"status": "completed"},
|
||||
"next_step": None,
|
||||
"celebration": celebration,
|
||||
}), 200
|
||||
postgres.update("routine_sessions", {"current_step_index": next_index}, {"id": session_id})
|
||||
return flask.jsonify({"session": {"current_step_index": next_index}, "next_step": steps[next_index]}), 200
|
||||
celebration = _complete_session_with_celebration(
|
||||
session_id, user_uuid, session
|
||||
)
|
||||
return flask.jsonify(
|
||||
{
|
||||
"session": {"status": "completed"},
|
||||
"next_step": None,
|
||||
"celebration": celebration,
|
||||
}
|
||||
), 200
|
||||
postgres.update(
|
||||
"routine_sessions", {"current_step_index": next_index}, {"id": session_id}
|
||||
)
|
||||
return flask.jsonify(
|
||||
{
|
||||
"session": {"current_step_index": next_index},
|
||||
"next_step": steps[next_index],
|
||||
}
|
||||
), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>/skip-step", methods=["POST"])
|
||||
def api_skipStep(session_id):
|
||||
@@ -441,14 +531,20 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
session = postgres.select_one("routine_sessions", {"id": session_id, "user_uuid": user_uuid})
|
||||
session = postgres.select_one(
|
||||
"routine_sessions", {"id": session_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not session:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
if session["status"] not in ("active", "paused"):
|
||||
return flask.jsonify({"error": "session not active"}), 400
|
||||
# Auto-resume if paused
|
||||
if session["status"] == "paused":
|
||||
postgres.update("routine_sessions", {"status": "active", "paused_at": None}, {"id": session_id})
|
||||
postgres.update(
|
||||
"routine_sessions",
|
||||
{"status": "active", "paused_at": None},
|
||||
{"id": session_id},
|
||||
)
|
||||
steps = postgres.select(
|
||||
"routine_steps",
|
||||
where={"routine_id": session["routine_id"]},
|
||||
@@ -459,18 +555,31 @@ def register(app):
|
||||
|
||||
# Record step result as skipped
|
||||
if current_step:
|
||||
_record_step_result(session_id, current_step["id"], current_index, "skipped", session)
|
||||
_record_step_result(
|
||||
session_id, current_step["id"], current_index, "skipped", session
|
||||
)
|
||||
|
||||
next_index = current_index + 1
|
||||
if next_index >= len(steps):
|
||||
celebration = _complete_session_with_celebration(session_id, user_uuid, session)
|
||||
return flask.jsonify({
|
||||
"session": {"status": "completed"},
|
||||
"next_step": None,
|
||||
"celebration": celebration,
|
||||
}), 200
|
||||
postgres.update("routine_sessions", {"current_step_index": next_index}, {"id": session_id})
|
||||
return flask.jsonify({"session": {"current_step_index": next_index}, "next_step": steps[next_index]}), 200
|
||||
celebration = _complete_session_with_celebration(
|
||||
session_id, user_uuid, session
|
||||
)
|
||||
return flask.jsonify(
|
||||
{
|
||||
"session": {"status": "completed"},
|
||||
"next_step": None,
|
||||
"celebration": celebration,
|
||||
}
|
||||
), 200
|
||||
postgres.update(
|
||||
"routine_sessions", {"current_step_index": next_index}, {"id": session_id}
|
||||
)
|
||||
return flask.jsonify(
|
||||
{
|
||||
"session": {"current_step_index": next_index},
|
||||
"next_step": steps[next_index],
|
||||
}
|
||||
), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>/cancel", methods=["POST"])
|
||||
def api_cancelSession(session_id):
|
||||
@@ -478,7 +587,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
session = postgres.select_one("routine_sessions", {"id": session_id, "user_uuid": user_uuid})
|
||||
session = postgres.select_one(
|
||||
"routine_sessions", {"id": session_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not session:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
postgres.update("routine_sessions", {"status": "cancelled"}, {"id": session_id})
|
||||
@@ -492,7 +603,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
days = flask.request.args.get("days", 7, type=int)
|
||||
@@ -523,15 +636,17 @@ def register(app):
|
||||
continue
|
||||
steps = postgres.select("routine_steps", where={"routine_id": r["id"]})
|
||||
total_duration = sum(s.get("duration_minutes") or 0 for s in steps)
|
||||
result.append({
|
||||
"routine_id": r["id"],
|
||||
"routine_name": r.get("name", ""),
|
||||
"routine_icon": r.get("icon", ""),
|
||||
"days": sched.get("days", []),
|
||||
"time": sched.get("time"),
|
||||
"remind": sched.get("remind", True),
|
||||
"total_duration_minutes": total_duration,
|
||||
})
|
||||
result.append(
|
||||
{
|
||||
"routine_id": r["id"],
|
||||
"routine_name": r.get("name", ""),
|
||||
"routine_icon": r.get("icon", ""),
|
||||
"days": sched.get("days", []),
|
||||
"time": sched.get("time"),
|
||||
"remind": sched.get("remind", True),
|
||||
"total_duration_minutes": total_duration,
|
||||
}
|
||||
)
|
||||
return flask.jsonify(result), 200
|
||||
|
||||
@app.route("/api/routines/<routine_id>/schedule", methods=["PUT"])
|
||||
@@ -540,7 +655,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
data = flask.request.get_json()
|
||||
@@ -549,12 +666,14 @@ def register(app):
|
||||
existing = postgres.select_one("routine_schedules", {"routine_id": routine_id})
|
||||
schedule_data = {
|
||||
"routine_id": routine_id,
|
||||
"days": data.get("days", []),
|
||||
"days": json.dumps(data.get("days", [])),
|
||||
"time": data.get("time"),
|
||||
"remind": data.get("remind", True),
|
||||
}
|
||||
if existing:
|
||||
result = postgres.update("routine_schedules", schedule_data, {"routine_id": routine_id})
|
||||
result = postgres.update(
|
||||
"routine_schedules", schedule_data, {"routine_id": routine_id}
|
||||
)
|
||||
return flask.jsonify(result[0] if result else {}), 200
|
||||
else:
|
||||
schedule_data["id"] = str(uuid.uuid4())
|
||||
@@ -567,7 +686,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
schedule = postgres.select_one("routine_schedules", {"routine_id": routine_id})
|
||||
@@ -581,7 +702,9 @@ def register(app):
|
||||
user_uuid = _auth(flask.request)
|
||||
if not user_uuid:
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
routine = postgres.select_one("routines", {"id": routine_id, "user_uuid": user_uuid})
|
||||
routine = postgres.select_one(
|
||||
"routines", {"id": routine_id, "user_uuid": user_uuid}
|
||||
)
|
||||
if not routine:
|
||||
return flask.jsonify({"error": "not found"}), 404
|
||||
postgres.delete("routine_schedules", {"routine_id": routine_id})
|
||||
|
||||
Reference in New Issue
Block a user