from __future__ import annotations from flask import Blueprint, abort, jsonify, redirect, render_template, request, url_for from flask_login import current_user from app.extensions import db from app.models import AttendanceEvent, AttendanceType, Person, Role from app.services.attendance import last_presence_summary, record_attendance from app.services.security import roles_required bp = Blueprint("attendance", __name__, url_prefix="/attendance") @bp.get("/") @roles_required(Role.ADMIN, Role.OPERATOR, Role.VIEWER) def index(): events = AttendanceEvent.query.order_by(AttendanceEvent.occurred_at.desc()).limit(250).all() return render_template("attendance/index.html", events=events) @bp.get("/kiosk") @roles_required(Role.ADMIN, Role.OPERATOR) def kiosk(): return render_template("attendance/kiosk.html") @bp.post("/events") @roles_required(Role.ADMIN, Role.OPERATOR) def create_event(): person_id = request.form.get("person_id", type=int) raw_event_type = request.form.get("event_type", "") confidence = request.form.get("confidence", type=float) person = db.session.get(Person, person_id) if person_id else None if not person or not person.active: abort(404) try: event_type = AttendanceType(raw_event_type) except ValueError: abort(400) event = record_attendance( person, event_type, created_by_id=current_user.id, confidence=confidence, source="web-kiosk", ) if request.accept_mimetypes.accept_json: return jsonify( { "id": event.id, "event_type": event.type_label, "occurred_at": event.occurred_at.strftime("%Y-%m-%d %H:%M"), "summary": last_presence_summary(person), } ) return redirect(url_for("attendance.index"))