from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlmodel import Session, select from database import get_session from models import Attendance, User, Show from schemas import AttendanceCreate, AttendanceRead from auth import get_current_user from services.gamification import award_xp, check_and_award_badges, update_streak, XP_REWARDS router = APIRouter(prefix="/attendance", tags=["attendance"]) @router.post("/", response_model=AttendanceRead) def mark_attendance( attendance: AttendanceCreate, session: Session = Depends(get_session), current_user: User = Depends(get_current_user) ): # Check if already attended existing = session.exec( select(Attendance) .where(Attendance.user_id == current_user.id) .where(Attendance.show_id == attendance.show_id) ).first() if existing: # Update notes if provided, or just return existing if attendance.notes: existing.notes = attendance.notes session.add(existing) session.commit() session.refresh(existing) return existing db_attendance = Attendance(**attendance.model_dump(), user_id=current_user.id) session.add(db_attendance) # Award XP for marking attendance new_xp, level_up = award_xp(session, current_user, XP_REWARDS["attendance_add"], "attendance") update_streak(session, current_user) new_badges = check_and_award_badges(session, current_user) session.commit() session.refresh(db_attendance) return db_attendance @router.delete("/{show_id}") def remove_attendance( show_id: int, session: Session = Depends(get_session), current_user: User = Depends(get_current_user) ): attendance = session.exec( select(Attendance) .where(Attendance.user_id == current_user.id) .where(Attendance.show_id == show_id) ).first() if not attendance: raise HTTPException(status_code=404, detail="Attendance not found") session.delete(attendance) session.commit() return {"ok": True} @router.get("/me", response_model=List[AttendanceRead]) def get_my_attendance( session: Session = Depends(get_session), current_user: User = Depends(get_current_user) ): return session.exec(select(Attendance).where(Attendance.user_id == current_user.id)).all() @router.get("/show/{show_id}", response_model=List[AttendanceRead]) def get_show_attendance( show_id: int, session: Session = Depends(get_session), offset: int = 0, limit: int = 100 ): return session.exec( select(Attendance) .where(Attendance.show_id == show_id) .offset(offset) .limit(limit) ).all() @router.get("/me/stats") def get_my_attendance_stats( session: Session = Depends(get_session), current_user: User = Depends(get_current_user) ): """Get attendance statistics grouped by band""" from models import Vertical attendances = session.exec( select(Attendance).where(Attendance.user_id == current_user.id) ).all() total = len(attendances) by_vertical = {} years = set() for a in attendances: show = session.get(Show, a.show_id) if not show: continue if show.date: years.add(show.date.year) vertical = session.get(Vertical, show.vertical_id) if vertical: if vertical.slug not in by_vertical: by_vertical[vertical.slug] = { "name": vertical.name, "count": 0 } by_vertical[vertical.slug]["count"] += 1 return { "total_shows": total, "by_vertical": by_vertical, "years_attended": sorted(years, reverse=True), "year_count": len(years) }