from flask import Blueprint, request, jsonify from server.database import Session from models.models import SchoolHoliday from datetime import datetime import csv import io holidays_bp = Blueprint("holidays", __name__, url_prefix="/api/holidays") @holidays_bp.route("", methods=["GET"]) def list_holidays(): session = Session() region = request.args.get("region") q = session.query(SchoolHoliday) if region: q = q.filter(SchoolHoliday.region == region) rows = q.order_by(SchoolHoliday.start_date.asc()).all() data = [r.to_dict() for r in rows] session.close() return jsonify({"holidays": data}) @holidays_bp.route("/upload", methods=["POST"]) def upload_holidays(): """ Accepts a CSV file upload (multipart/form-data) with columns like: name,start_date,end_date,region Dates can be in ISO (YYYY-MM-DD) or common European format (DD.MM.YYYY). """ if "file" not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files["file"] if file.filename == "": return jsonify({"error": "No selected file"}), 400 try: content = file.read().decode("utf-8", errors="ignore") # Try to auto-detect delimiter; default ',' sniffer = csv.Sniffer() dialect = None try: dialect = sniffer.sniff(content[:1024]) except Exception: pass reader = csv.DictReader(io.StringIO( content), dialect=dialect) if dialect else csv.DictReader(io.StringIO(content)) required = {"name", "start_date", "end_date"} if not required.issubset(set(h.lower() for h in reader.fieldnames or [])): return jsonify({"error": "CSV must contain headers: name, start_date, end_date"}), 400 def parse_date(s: str): s = (s or "").strip() if not s: return None # Try ISO first for fmt in ("%Y-%m-%d", "%d.%m.%Y", "%Y/%m/%d"): try: return datetime.strptime(s, fmt).date() except ValueError: continue raise ValueError(f"Unsupported date format: {s}") session = Session() inserted = 0 updated = 0 for row in reader: # Normalize headers to lower-case keys norm = {k.lower(): (v or "").strip() for k, v in row.items()} name = norm.get("name") start_date = parse_date(norm.get("start_date")) end_date = parse_date(norm.get("end_date")) region = norm.get("region") or None if not name or not start_date or not end_date: continue existing = ( session.query(SchoolHoliday) .filter( SchoolHoliday.name == name, SchoolHoliday.start_date == start_date, SchoolHoliday.end_date == end_date, SchoolHoliday.region.is_( region) if region is None else SchoolHoliday.region == region, ) .first() ) if existing: # Optionally update region or source_file_name existing.region = region existing.source_file_name = file.filename updated += 1 else: session.add(SchoolHoliday( name=name, start_date=start_date, end_date=end_date, region=region, source_file_name=file.filename, )) inserted += 1 session.commit() session.close() return jsonify({"success": True, "inserted": inserted, "updated": updated}) except Exception as e: return jsonify({"error": str(e)}), 400