Files
infoscreen/server/routes/event_exceptions.py
RobbStarkAustria 773628c324 feat(events): reliable holiday skipping for recurrences + UI badge; clean logs
Backend: generate EventException on create/update when skip_holidays or recurrence changes; emit RecurrenceException (EXDATE) with exact occurrence start time (UTC)
API: return master events with RecurrenceRule + RecurrenceException
Frontend: map RecurrenceException → recurrenceException; ensure SkipHolidays instances never render on holidays; place TentTree icon (black) next to main event icon via template
Docs: update README and Copilot instructions for recurrence/holiday behavior
Cleanup: remove dataSource and debug console logs
2025-10-12 12:00:43 +00:00

114 lines
4.7 KiB
Python

from flask import Blueprint, request, jsonify
from server.database import Session
from models.models import EventException, Event
from datetime import datetime, date
event_exceptions_bp = Blueprint("event_exceptions", __name__, url_prefix="/api/event_exceptions")
@event_exceptions_bp.route("", methods=["POST"])
def create_exception():
data = request.json
session = Session()
# required: event_id, exception_date
required = ["event_id", "exception_date"]
for f in required:
if f not in data:
return jsonify({"error": f"Missing field: {f}"}), 400
# Validate event exists
event = session.query(Event).filter_by(id=data["event_id"]).first()
if not event:
session.close()
return jsonify({"error": "Event not found"}), 404
exc_date = datetime.fromisoformat(data["exception_date"]).date() if isinstance(data["exception_date"], str) else data["exception_date"]
# Check if an exception for this event and date already exists
existing_exc = session.query(EventException).filter_by(event_id=event.id, exception_date=exc_date).first()
if existing_exc:
# Optionally, update the existing exception fields if needed
existing_exc.is_skipped = bool(data.get("is_skipped", existing_exc.is_skipped))
existing_exc.override_title = data.get("override_title", existing_exc.override_title)
existing_exc.override_description = data.get("override_description", existing_exc.override_description)
existing_exc.override_start = datetime.fromisoformat(data["override_start"]) if data.get("override_start") else existing_exc.override_start
existing_exc.override_end = datetime.fromisoformat(data["override_end"]) if data.get("override_end") else existing_exc.override_end
session.commit()
return jsonify({"success": True, "id": existing_exc.id, "updated": True})
# Otherwise, create a new exception
exc = EventException(
event_id=event.id,
exception_date=exc_date,
is_skipped=bool(data.get("is_skipped", False)),
override_title=data.get("override_title"),
override_description=data.get("override_description"),
override_start=(datetime.fromisoformat(data["override_start"]) if data.get("override_start") else None),
override_end=(datetime.fromisoformat(data["override_end"]) if data.get("override_end") else None),
)
session.add(exc)
session.commit()
return jsonify({"success": True, "id": exc.id})
@event_exceptions_bp.route("/<exc_id>", methods=["PUT"])
def update_exception(exc_id):
data = request.json
session = Session()
exc = session.query(EventException).filter_by(id=exc_id).first()
if not exc:
session.close()
return jsonify({"error": "Exception not found"}), 404
if "exception_date" in data:
exc.exception_date = datetime.fromisoformat(data["exception_date"]).date()
if "is_skipped" in data:
exc.is_skipped = bool(data["is_skipped"])
if "override_title" in data:
exc.override_title = data.get("override_title")
if "override_description" in data:
exc.override_description = data.get("override_description")
if "override_start" in data:
exc.override_start = datetime.fromisoformat(data["override_start"]) if data.get("override_start") else None
if "override_end" in data:
exc.override_end = datetime.fromisoformat(data["override_end"]) if data.get("override_end") else None
session.commit()
session.close()
return jsonify({"success": True})
@event_exceptions_bp.route("/<exc_id>", methods=["DELETE"])
def delete_exception(exc_id):
session = Session()
exc = session.query(EventException).filter_by(id=exc_id).first()
if not exc:
session.close()
return jsonify({"error": "Exception not found"}), 404
session.delete(exc)
session.commit()
session.close()
return jsonify({"success": True})
@event_exceptions_bp.route("", methods=["GET"])
def list_exceptions():
session = Session()
event_id = request.args.get("event_id")
q = session.query(EventException)
if event_id:
q = q.filter(EventException.event_id == int(event_id))
rows = q.all()
out = []
for r in rows:
out.append({
"id": r.id,
"event_id": r.event_id,
"exception_date": r.exception_date.isoformat(),
"is_skipped": r.is_skipped,
"override_title": r.override_title,
"override_description": r.override_description,
"override_start": r.override_start.isoformat() if r.override_start else None,
"override_end": r.override_end.isoformat() if r.override_end else None,
})
session.close()
return jsonify(out)