First synculous 2 Big-Pickle pass.

This commit is contained in:
2026-02-12 23:07:48 -06:00
parent 25d05e0e86
commit 3e1134575b
26 changed files with 2729 additions and 59 deletions

View File

@@ -5,6 +5,7 @@ Routines have ordered steps. Users start sessions to walk through them.
"""
import os
import uuid
import flask
import jwt
import core.auth as auth
@@ -41,7 +42,8 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
routines = postgres.select("routines", where={"user_uuid": user_uuid}, order_by="name")
return flask.jsonify(routines), 200
@app.route("/api/routines", methods=["POST"])
def api_createRoutine():
@@ -50,7 +52,14 @@ def register(app):
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
data = flask.request.get_json()
pass
if not data:
return flask.jsonify({"error": "missing body"}), 400
if not data.get("name"):
return flask.jsonify({"error": "missing required field: name"}), 400
data["id"] = str(uuid.uuid4())
data["user_uuid"] = user_uuid
routine = postgres.insert("routines", data)
return flask.jsonify(routine), 201
@app.route("/api/routines/<routine_id>", methods=["GET"])
def api_getRoutine(routine_id):
@@ -58,7 +67,15 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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(
"routine_steps",
where={"routine_id": routine_id},
order_by="position",
)
return flask.jsonify({"routine": routine, "steps": steps}), 200
@app.route("/api/routines/<routine_id>", methods=["PUT"])
def api_updateRoutine(routine_id):
@@ -67,7 +84,17 @@ def register(app):
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
data = flask.request.get_json()
pass
if not data:
return flask.jsonify({"error": "missing body"}), 400
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"]
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})
return flask.jsonify(result[0] if result else {}), 200
@app.route("/api/routines/<routine_id>", methods=["DELETE"])
def api_deleteRoutine(routine_id):
@@ -75,7 +102,14 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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})
postgres.delete("routine_steps", {"routine_id": routine_id})
postgres.delete("routine_schedules", {"routine_id": routine_id})
postgres.delete("routines", {"id": routine_id, "user_uuid": user_uuid})
return flask.jsonify({"deleted": True}), 200
# ── Steps CRUD ────────────────────────────────────────────────
@@ -85,7 +119,15 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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(
"routine_steps",
where={"routine_id": routine_id},
order_by="position",
)
return flask.jsonify(steps), 200
@app.route("/api/routines/<routine_id>/steps", methods=["POST"])
def api_addStep(routine_id):
@@ -93,8 +135,30 @@ 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})
if not routine:
return flask.jsonify({"error": "not found"}), 404
data = flask.request.get_json()
pass
if not data:
return flask.jsonify({"error": "missing body"}), 400
if not data.get("name"):
return flask.jsonify({"error": "missing required field: name"}), 400
max_pos = postgres.select(
"routine_steps",
where={"routine_id": routine_id},
order_by="position DESC",
limit=1,
)
next_pos = (max_pos[0]["position"] + 1) if max_pos else 1
step = {
"id": str(uuid.uuid4()),
"routine_id": routine_id,
"name": data["name"],
"duration_minutes": data.get("duration_minutes"),
"position": data.get("position", next_pos),
}
result = postgres.insert("routine_steps", step)
return flask.jsonify(result), 201
@app.route("/api/routines/<routine_id>/steps/<step_id>", methods=["PUT"])
def api_updateStep(routine_id, step_id):
@@ -102,8 +166,21 @@ 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})
if not routine:
return flask.jsonify({"error": "not found"}), 404
data = flask.request.get_json()
pass
if not data:
return flask.jsonify({"error": "missing body"}), 400
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})
return flask.jsonify(result[0] if result else {}), 200
@app.route("/api/routines/<routine_id>/steps/<step_id>", methods=["DELETE"])
def api_deleteStep(routine_id, step_id):
@@ -111,7 +188,14 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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})
if not existing:
return flask.jsonify({"error": "step not found"}), 404
postgres.delete("routine_steps", {"id": step_id, "routine_id": routine_id})
return flask.jsonify({"deleted": True}), 200
@app.route("/api/routines/<routine_id>/steps/reorder", methods=["PUT"])
def api_reorderSteps(routine_id):
@@ -119,8 +203,21 @@ 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})
if not routine:
return flask.jsonify({"error": "not found"}), 404
data = flask.request.get_json()
pass
if not data or not data.get("step_ids"):
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})
steps = postgres.select(
"routine_steps",
where={"routine_id": routine_id},
order_by="position",
)
return flask.jsonify(steps), 200
# ── Routine Sessions (active run-through) ─────────────────────
@@ -130,7 +227,28 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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"})
if active:
return flask.jsonify({"error": "already have active session", "session_id": active["id"]}), 409
steps = postgres.select(
"routine_steps",
where={"routine_id": routine_id},
order_by="position",
)
if not steps:
return flask.jsonify({"error": "no steps in routine"}), 400
session = {
"id": str(uuid.uuid4()),
"routine_id": routine_id,
"user_uuid": user_uuid,
"status": "active",
"current_step_index": 0,
}
result = postgres.insert("routine_sessions", session)
return flask.jsonify({"session": result, "current_step": steps[0]}), 201
@app.route("/api/sessions/active", methods=["GET"])
def api_getActiveSession():
@@ -138,7 +256,17 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
session = postgres.select_one("routine_sessions", {"user_uuid": user_uuid, "status": "active"})
if not session:
return flask.jsonify({"error": "no active session"}), 404
routine = postgres.select_one("routines", {"id": session["routine_id"]})
steps = postgres.select(
"routine_steps",
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
@app.route("/api/sessions/<session_id>/complete-step", methods=["POST"])
def api_completeStep(session_id):
@@ -146,8 +274,23 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
data = flask.request.get_json()
pass
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"] != "active":
return flask.jsonify({"error": "session not active"}), 400
data = flask.request.get_json() or {}
steps = postgres.select(
"routine_steps",
where={"routine_id": session["routine_id"]},
order_by="position",
)
next_index = session["current_step_index"] + 1
if next_index >= len(steps):
postgres.update("routine_sessions", {"status": "completed"}, {"id": session_id})
return flask.jsonify({"session": {"status": "completed"}, "next_step": None}), 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):
@@ -155,8 +298,22 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
data = flask.request.get_json()
pass
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"] != "active":
return flask.jsonify({"error": "session not active"}), 400
steps = postgres.select(
"routine_steps",
where={"routine_id": session["routine_id"]},
order_by="position",
)
next_index = session["current_step_index"] + 1
if next_index >= len(steps):
postgres.update("routine_sessions", {"status": "completed"}, {"id": session_id})
return flask.jsonify({"session": {"status": "completed"}, "next_step": None}), 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):
@@ -164,7 +321,11 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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})
return flask.jsonify({"session": {"status": "cancelled"}}), 200
# ── Routine History / Stats ───────────────────────────────────
@@ -174,7 +335,17 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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)
sessions = postgres.select(
"routine_sessions",
where={"routine_id": routine_id},
order_by="created_at DESC",
limit=days,
)
return flask.jsonify(sessions), 200
# ── Routine Scheduling ────────────────────────────────────────
@@ -184,8 +355,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})
if not routine:
return flask.jsonify({"error": "not found"}), 404
data = flask.request.get_json()
pass
if not data:
return flask.jsonify({"error": "missing body"}), 400
existing = postgres.select_one("routine_schedules", {"routine_id": routine_id})
schedule_data = {
"routine_id": routine_id,
"days": 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})
return flask.jsonify(result[0] if result else {}), 200
else:
schedule_data["id"] = str(uuid.uuid4())
result = postgres.insert("routine_schedules", schedule_data)
return flask.jsonify(result), 201
@app.route("/api/routines/<routine_id>/schedule", methods=["GET"])
def api_getRoutineSchedule(routine_id):
@@ -193,7 +382,13 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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})
if not schedule:
return flask.jsonify({"error": "no schedule set"}), 404
return flask.jsonify(schedule), 200
@app.route("/api/routines/<routine_id>/schedule", methods=["DELETE"])
def api_deleteRoutineSchedule(routine_id):
@@ -201,4 +396,8 @@ def register(app):
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
pass
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})
return flask.jsonify({"deleted": True}), 200