First synculous 2 Big-Pickle pass.
This commit is contained in:
149
api/routes/routine_sessions_extended.py
Normal file
149
api/routes/routine_sessions_extended.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""
|
||||
Routine Sessions Extended API - pause, resume, abort, notes, duration tracking
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
import flask
|
||||
import jwt
|
||||
import core.auth as auth
|
||||
import core.postgres as postgres
|
||||
|
||||
|
||||
def _get_user_uuid(token):
|
||||
try:
|
||||
payload = jwt.decode(token, os.getenv("JWT_SECRET"), algorithms=["HS256"])
|
||||
return payload.get("sub")
|
||||
except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
|
||||
return None
|
||||
|
||||
|
||||
def _auth(request):
|
||||
header = request.headers.get("Authorization", "")
|
||||
if not header.startswith("Bearer "):
|
||||
return None
|
||||
token = header[7:]
|
||||
user_uuid = _get_user_uuid(token)
|
||||
if not user_uuid or not auth.verifyLoginToken(token, userUUID=user_uuid):
|
||||
return None
|
||||
return user_uuid
|
||||
|
||||
|
||||
def register(app):
|
||||
|
||||
@app.route("/api/sessions/<session_id>/pause", methods=["POST"])
|
||||
def api_pauseSession(session_id):
|
||||
"""Pause an active session."""
|
||||
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})
|
||||
if not session:
|
||||
return flask.jsonify({"error": "session not found"}), 404
|
||||
if session.get("status") != "active":
|
||||
return flask.jsonify({"error": "session not active"}), 400
|
||||
result = postgres.update(
|
||||
"routine_sessions",
|
||||
{"status": "paused", "paused_at": datetime.now().isoformat()},
|
||||
{"id": session_id}
|
||||
)
|
||||
return flask.jsonify({"status": "paused"}), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>/resume", methods=["POST"])
|
||||
def api_resumeSession(session_id):
|
||||
"""Resume a paused session."""
|
||||
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})
|
||||
if not session:
|
||||
return flask.jsonify({"error": "session not found"}), 404
|
||||
if session.get("status") != "paused":
|
||||
return flask.jsonify({"error": "session not paused"}), 400
|
||||
result = postgres.update(
|
||||
"routine_sessions",
|
||||
{"status": "active", "paused_at": None},
|
||||
{"id": session_id}
|
||||
)
|
||||
return flask.jsonify({"status": "active"}), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>/abort", methods=["POST"])
|
||||
def api_abortSession(session_id):
|
||||
"""Abort a session with reason. Body: {reason: string}"""
|
||||
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})
|
||||
if not session:
|
||||
return flask.jsonify({"error": "session not found"}), 404
|
||||
data = flask.request.get_json() or {}
|
||||
reason = data.get("reason", "Aborted by user")
|
||||
result = postgres.update(
|
||||
"routine_sessions",
|
||||
{"status": "aborted", "abort_reason": reason, "completed_at": datetime.now().isoformat()},
|
||||
{"id": session_id}
|
||||
)
|
||||
return flask.jsonify({"status": "aborted", "reason": reason}), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>/note", methods=["POST"])
|
||||
def api_addSessionNote(session_id):
|
||||
"""Add a note to the session. Body: {step_index: int, note: string}"""
|
||||
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})
|
||||
if not session:
|
||||
return flask.jsonify({"error": "session not found"}), 404
|
||||
data = flask.request.get_json()
|
||||
if not data or not data.get("note"):
|
||||
return flask.jsonify({"error": "missing note"}), 400
|
||||
note_entry = {
|
||||
"id": str(uuid.uuid4()),
|
||||
"session_id": session_id,
|
||||
"step_index": data.get("step_index"),
|
||||
"note": data["note"],
|
||||
}
|
||||
note = postgres.insert("routine_session_notes", note_entry)
|
||||
return flask.jsonify(note), 201
|
||||
|
||||
@app.route("/api/sessions/<session_id>/duration", methods=["PUT"])
|
||||
def api_setSessionDuration(session_id):
|
||||
"""Record actual duration. Body: {actual_duration_minutes: int}"""
|
||||
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})
|
||||
if not session:
|
||||
return flask.jsonify({"error": "session not found"}), 404
|
||||
data = flask.request.get_json()
|
||||
if not data:
|
||||
return flask.jsonify({"error": "missing body"}), 400
|
||||
duration = data.get("actual_duration_minutes")
|
||||
if duration is None:
|
||||
return flask.jsonify({"error": "missing actual_duration_minutes"}), 400
|
||||
result = postgres.update(
|
||||
"routine_sessions",
|
||||
{"actual_duration_minutes": duration},
|
||||
{"id": session_id}
|
||||
)
|
||||
return flask.jsonify(result[0] if result else {}), 200
|
||||
|
||||
@app.route("/api/sessions/<session_id>", methods=["GET"])
|
||||
def api_getSessionDetails(session_id):
|
||||
"""Get session details with all notes."""
|
||||
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})
|
||||
if not session:
|
||||
return flask.jsonify({"error": "session not found"}), 404
|
||||
notes = postgres.select("routine_session_notes", {"session_id": session_id}, order_by="created_at")
|
||||
routine = postgres.select_one("routines", {"id": session["routine_id"]})
|
||||
steps = postgres.select("routine_steps", {"routine_id": session["routine_id"]}, order_by="position")
|
||||
return flask.jsonify({
|
||||
"session": session,
|
||||
"routine": routine,
|
||||
"steps": steps,
|
||||
"notes": notes,
|
||||
}), 200
|
||||
Reference in New Issue
Block a user