Add adaptive medication timing, Discord presence tracking, and nagging system
This commit is contained in:
185
api/routes/adaptive_meds.py
Normal file
185
api/routes/adaptive_meds.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user