""" 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//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//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//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//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//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/", 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