diff --git a/src/fabledassistant/routes/events.py b/src/fabledassistant/routes/events.py index 7c9ef4e..4108f3e 100644 --- a/src/fabledassistant/routes/events.py +++ b/src/fabledassistant/routes/events.py @@ -1,7 +1,7 @@ """Calendar events REST API.""" from __future__ import annotations -from datetime import datetime +from datetime import datetime, timezone from quart import Blueprint, g, jsonify, request @@ -11,6 +11,14 @@ import fabledassistant.services.events as events_svc events_bp = Blueprint("events", __name__, url_prefix="/api/events") +def _parse_dt(value: str) -> datetime: + """Parse ISO 8601 datetime string, ensuring UTC-awareness.""" + dt = datetime.fromisoformat(value.replace("Z", "+00:00")) + if dt.tzinfo is None: + dt = dt.replace(tzinfo=timezone.utc) + return dt + + def _get_current_user_id() -> int: return g.user.id @@ -23,8 +31,8 @@ async def list_events(): if not date_from_str or not date_to_str: return jsonify({"error": "from and to query params are required"}), 400 try: - date_from = datetime.fromisoformat(date_from_str) - date_to = datetime.fromisoformat(date_to_str) + date_from = _parse_dt(date_from_str) + date_to = _parse_dt(date_to_str) except ValueError: return jsonify({"error": "Invalid datetime format"}), 400 events = await events_svc.list_events( @@ -42,8 +50,8 @@ async def create_event(): if not data.get("title") or not data.get("start_dt"): return jsonify({"error": "title and start_dt are required"}), 400 try: - start_dt = datetime.fromisoformat(data["start_dt"]) - end_dt = datetime.fromisoformat(data["end_dt"]) if data.get("end_dt") else None + start_dt = _parse_dt(data["start_dt"]) + end_dt = _parse_dt(data["end_dt"]) if data.get("end_dt") else None except ValueError: return jsonify({"error": "Invalid datetime format"}), 400 event = await events_svc.create_event( @@ -90,7 +98,7 @@ async def update_event(event_id: int): for dt_field in ("start_dt", "end_dt"): if dt_field in data and data[dt_field]: try: - fields[dt_field] = datetime.fromisoformat(data[dt_field]) + fields[dt_field] = _parse_dt(data[dt_field]) except ValueError: return jsonify({"error": f"Invalid datetime for {dt_field}"}), 400 event = await events_svc.update_event(