from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from typing import List from database import get_db from models.flag import TableFlagDef, TableFlagAssignment from schemas.flag import FlagDefCreate, FlagDefUpdate, FlagDefOut, FlagAssignmentOut, SetTableFlagsRequest from routers.deps import get_current_user, require_manager from models.user import User router = APIRouter() # ─── Flag definitions (manager only) ───────────────────────────────────────── @router.get("/defs", response_model=List[FlagDefOut]) def list_flag_defs( include_inactive: bool = False, db: Session = Depends(get_db), user: User = Depends(get_current_user), ): q = db.query(TableFlagDef) if not include_inactive: q = q.filter(TableFlagDef.is_active == True) return q.order_by(TableFlagDef.sort_order, TableFlagDef.id).all() @router.post("/defs", response_model=FlagDefOut, status_code=status.HTTP_201_CREATED) def create_flag_def( body: FlagDefCreate, db: Session = Depends(get_db), user: User = Depends(require_manager), ): flag = TableFlagDef(**body.model_dump()) db.add(flag) db.commit() db.refresh(flag) return flag @router.put("/defs/{flag_id}", response_model=FlagDefOut) def update_flag_def( flag_id: int, body: FlagDefUpdate, db: Session = Depends(get_db), user: User = Depends(require_manager), ): flag = db.query(TableFlagDef).filter(TableFlagDef.id == flag_id).first() if not flag: raise HTTPException(status_code=404, detail="Flag not found") for k, v in body.model_dump(exclude_unset=True).items(): setattr(flag, k, v) db.commit() db.refresh(flag) return flag @router.delete("/defs/{flag_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_flag_def( flag_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager), ): flag = db.query(TableFlagDef).filter(TableFlagDef.id == flag_id).first() if not flag: raise HTTPException(status_code=404, detail="Flag not found") # Soft delete — keeps existing assignments readable flag.is_active = False db.commit() # ─── All assignments (bulk endpoint for manager views) ─────────────────────── @router.get("/assignments", response_model=List[FlagAssignmentOut]) def get_all_assignments( db: Session = Depends(get_db), user: User = Depends(get_current_user), ): """All active flag assignments across all tables (for manager dashboard bulk load).""" return db.query(TableFlagAssignment).all() # ─── Table flag assignments ─────────────────────────────────────────────────── @router.get("/table/{table_id}", response_model=List[FlagAssignmentOut]) def get_table_flags( table_id: int, db: Session = Depends(get_db), user: User = Depends(get_current_user), ): return db.query(TableFlagAssignment).filter( TableFlagAssignment.table_id == table_id ).all() @router.put("/table/{table_id}", response_model=List[FlagAssignmentOut]) def set_table_flags( table_id: int, body: SetTableFlagsRequest, db: Session = Depends(get_db), user: User = Depends(get_current_user), ): """Replace all flags on a table with the given set of flag_ids.""" # Validate all flag_ids exist and are active if body.flag_ids: valid = db.query(TableFlagDef).filter( TableFlagDef.id.in_(body.flag_ids), TableFlagDef.is_active == True, ).count() if valid != len(body.flag_ids): raise HTTPException(status_code=400, detail="One or more flag IDs are invalid") # Delete existing assignments for this table db.query(TableFlagAssignment).filter( TableFlagAssignment.table_id == table_id ).delete(synchronize_session=False) # Insert new assignments for flag_id in body.flag_ids: db.add(TableFlagAssignment( table_id=table_id, flag_id=flag_id, assigned_by=user.id, )) db.commit() return db.query(TableFlagAssignment).filter( TableFlagAssignment.table_id == table_id ).all() @router.delete("/table/{table_id}/all", status_code=status.HTTP_204_NO_CONTENT) def clear_table_flags( table_id: int, db: Session = Depends(get_db), user: User = Depends(get_current_user), ): db.query(TableFlagAssignment).filter( TableFlagAssignment.table_id == table_id ).delete(synchronize_session=False) db.commit()