186 lines
6.7 KiB
Python
186 lines
6.7 KiB
Python
"""
|
|
api/routes/adaptive_meds.py - API endpoints for adaptive medication settings
|
|
"""
|
|
|
|
import flask
|
|
import jwt
|
|
import os
|
|
import core.postgres as postgres
|
|
import core.adaptive_meds as adaptive_meds
|
|
|
|
JWT_SECRET = os.getenv("JWT_SECRET")
|
|
|
|
|
|
def _get_user_uuid(request):
|
|
"""Extract and validate user UUID from JWT token."""
|
|
auth_header = request.headers.get("Authorization", "")
|
|
if not auth_header.startswith("Bearer "):
|
|
return None
|
|
|
|
token = auth_header[7:]
|
|
try:
|
|
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
|
|
return payload.get("sub")
|
|
except jwt.ExpiredSignatureError:
|
|
return None
|
|
except jwt.InvalidTokenError:
|
|
return None
|
|
|
|
|
|
def register(app):
|
|
@app.route("/api/adaptive-meds/settings", methods=["GET"])
|
|
def get_adaptive_settings():
|
|
"""Get user's adaptive medication settings."""
|
|
user_uuid = _get_user_uuid(flask.request)
|
|
if not user_uuid:
|
|
return flask.jsonify({"error": "Unauthorized"}), 401
|
|
|
|
settings = adaptive_meds.get_adaptive_settings(user_uuid)
|
|
|
|
if not settings:
|
|
# Return defaults
|
|
return flask.jsonify(
|
|
{
|
|
"adaptive_timing_enabled": False,
|
|
"adaptive_mode": "shift_all",
|
|
"presence_tracking_enabled": False,
|
|
"nagging_enabled": True,
|
|
"nag_interval_minutes": 15,
|
|
"max_nag_count": 4,
|
|
"quiet_hours_start": None,
|
|
"quiet_hours_end": None,
|
|
}
|
|
), 200
|
|
|
|
return flask.jsonify(
|
|
{
|
|
"adaptive_timing_enabled": settings.get(
|
|
"adaptive_timing_enabled", False
|
|
),
|
|
"adaptive_mode": settings.get("adaptive_mode", "shift_all"),
|
|
"presence_tracking_enabled": settings.get(
|
|
"presence_tracking_enabled", False
|
|
),
|
|
"nagging_enabled": settings.get("nagging_enabled", True),
|
|
"nag_interval_minutes": settings.get("nag_interval_minutes", 15),
|
|
"max_nag_count": settings.get("max_nag_count", 4),
|
|
"quiet_hours_start": settings.get("quiet_hours_start"),
|
|
"quiet_hours_end": settings.get("quiet_hours_end"),
|
|
}
|
|
), 200
|
|
|
|
@app.route("/api/adaptive-meds/settings", methods=["PUT"])
|
|
def update_adaptive_settings():
|
|
"""Update user's adaptive medication settings."""
|
|
user_uuid = _get_user_uuid(flask.request)
|
|
if not user_uuid:
|
|
return flask.jsonify({"error": "Unauthorized"}), 401
|
|
|
|
data = flask.request.get_json()
|
|
if not data:
|
|
return flask.jsonify({"error": "No data provided"}), 400
|
|
|
|
# Validate required fields if enabling adaptive timing
|
|
if data.get("adaptive_timing_enabled"):
|
|
if not data.get("adaptive_mode"):
|
|
return flask.jsonify(
|
|
{"error": "adaptive_mode is required when enabling adaptive timing"}
|
|
), 400
|
|
|
|
# Build update data
|
|
update_data = {
|
|
"adaptive_timing_enabled": data.get("adaptive_timing_enabled", False),
|
|
"adaptive_mode": data.get("adaptive_mode", "shift_all"),
|
|
"presence_tracking_enabled": data.get("presence_tracking_enabled", False),
|
|
"nagging_enabled": data.get("nagging_enabled", True),
|
|
"nag_interval_minutes": data.get("nag_interval_minutes", 15),
|
|
"max_nag_count": data.get("max_nag_count", 4),
|
|
"quiet_hours_start": data.get("quiet_hours_start"),
|
|
"quiet_hours_end": data.get("quiet_hours_end"),
|
|
}
|
|
|
|
# Check if settings exist
|
|
existing = adaptive_meds.get_adaptive_settings(user_uuid)
|
|
|
|
if existing:
|
|
postgres.update(
|
|
"adaptive_med_settings", update_data, {"user_uuid": user_uuid}
|
|
)
|
|
else:
|
|
update_data["user_uuid"] = user_uuid
|
|
postgres.insert("adaptive_med_settings", update_data)
|
|
|
|
return flask.jsonify({"success": True}), 200
|
|
|
|
@app.route("/api/adaptive-meds/presence", methods=["GET"])
|
|
def get_presence_status():
|
|
"""Get user's Discord presence status."""
|
|
user_uuid = _get_user_uuid(flask.request)
|
|
if not user_uuid:
|
|
return flask.jsonify({"error": "Unauthorized"}), 401
|
|
|
|
presence = adaptive_meds.get_user_presence(user_uuid)
|
|
|
|
if not presence:
|
|
return flask.jsonify(
|
|
{"is_online": False, "last_online_at": None, "typical_wake_time": None}
|
|
), 200
|
|
|
|
typical_wake = adaptive_meds.calculate_typical_wake_time(user_uuid)
|
|
|
|
return flask.jsonify(
|
|
{
|
|
"is_online": presence.get("is_currently_online", False),
|
|
"last_online_at": presence.get("last_online_at").isoformat()
|
|
if presence.get("last_online_at")
|
|
else None,
|
|
"last_offline_at": presence.get("last_offline_at").isoformat()
|
|
if presence.get("last_offline_at")
|
|
else None,
|
|
"typical_wake_time": typical_wake.strftime("%H:%M")
|
|
if typical_wake
|
|
else None,
|
|
}
|
|
), 200
|
|
|
|
@app.route("/api/adaptive-meds/schedule", methods=["GET"])
|
|
def get_today_schedule():
|
|
"""Get today's adaptive medication schedule."""
|
|
user_uuid = _get_user_uuid(flask.request)
|
|
if not user_uuid:
|
|
return flask.jsonify({"error": "Unauthorized"}), 401
|
|
|
|
from datetime import date
|
|
|
|
today = date.today()
|
|
|
|
# Get all medications for user
|
|
meds = postgres.select("medications", {"user_uuid": user_uuid, "active": True})
|
|
|
|
schedule_data = []
|
|
for med in meds:
|
|
med_id = med.get("id")
|
|
med_schedules = postgres.select(
|
|
"medication_schedules",
|
|
{
|
|
"user_uuid": user_uuid,
|
|
"medication_id": med_id,
|
|
"adjustment_date": today,
|
|
},
|
|
)
|
|
|
|
for sched in med_schedules:
|
|
schedule_data.append(
|
|
{
|
|
"medication_id": med_id,
|
|
"medication_name": med.get("name"),
|
|
"base_time": sched.get("base_time"),
|
|
"adjusted_time": sched.get("adjusted_time"),
|
|
"adjustment_minutes": sched.get("adjustment_minutes", 0),
|
|
"status": sched.get("status", "pending"),
|
|
"nag_count": sched.get("nag_count", 0),
|
|
}
|
|
)
|
|
|
|
return flask.jsonify(schedule_data), 200
|