"""Problem Desk endpoints. Contract: outreach-frontend/lib/api/problems.ts.""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Query, Response, status from sqlalchemy.orm import Session from app.api.deps import get_current_user, get_db from app.crud import notifications as crud_notify from app.crud import problems as crud from app.models import User from app.schemas.problem import ( CreateCommentInput, CreateProblemInput, ProblemCommentOut, ProblemOut, UpdateProblemInput, ) router = APIRouter(tags=["problems"]) def _require(db: Session, problem_id: int): problem = crud.get_problem(db, problem_id) if problem is None: raise HTTPException(status_code=404, detail="Problem not found") return problem @router.get("/problems", response_model=list[ProblemOut]) def list_problems( priority: str = Query("all", max_length=60), status_filter: str = Query("Open", alias="status", max_length=32), # Today's embedded Priority Tracker card, personalized per person (2026-10-14) -- see # crud.list_problems_mentioning()'s own docstring. `priority` is ignored on this path (the Today card # never offers a priority filter, same as it never offered the full page's status tabs either). mentioned_me: bool = Query(False), db: Session = Depends(get_db), user: User | None = Depends(get_current_user), ): if mentioned_me: if user is None: return [] return [ ProblemOut.from_model(p, count) for p, count in crud.list_problems_mentioning(db, user.id, status_filter) ] return [ ProblemOut.from_model(p, count) for p, count in crud.list_problems(db, priority, status_filter) ] @router.post("/problems", response_model=ProblemOut, status_code=status.HTTP_201_CREATED) def create_problem( payload: CreateProblemInput, db: Session = Depends(get_db), user: User | None = Depends(get_current_user), ): problem = crud.create_problem(db, payload, user) crud_notify.notify_mentions( db, user, payload.mentions, payload.mention_team, text=f"{payload.title}. {payload.description}".strip(), problem_id=problem.id, ) return ProblemOut.from_model(problem, 0) @router.patch("/problems/{problem_id}", response_model=ProblemOut) def update_problem(problem_id: int, payload: UpdateProblemInput, db: Session = Depends(get_db)): problem = _require(db, problem_id) updated = crud.set_status(db, problem, payload.status) return ProblemOut.from_model(updated, crud.comment_count(db, problem_id)) @router.delete("/problems/{problem_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_problem(problem_id: int, db: Session = Depends(get_db)): crud.delete_problem(db, _require(db, problem_id)) return Response(status_code=status.HTTP_204_NO_CONTENT) @router.get("/problems/{problem_id}/comments", response_model=list[ProblemCommentOut]) def list_comments(problem_id: int, db: Session = Depends(get_db)): _require(db, problem_id) return [ProblemCommentOut.from_model(c) for c in crud.list_comments(db, problem_id)] @router.post( "/problems/{problem_id}/comments", response_model=ProblemCommentOut, status_code=status.HTTP_201_CREATED, ) def add_comment( problem_id: int, payload: CreateCommentInput, db: Session = Depends(get_db), user: User | None = Depends(get_current_user), ): _require(db, problem_id) comment = crud.add_comment(db, problem_id, payload, user) crud_notify.notify_mentions( db, user, payload.mentions, payload.mention_team, text=payload.comment_text, problem_id=problem_id ) return ProblemCommentOut.from_model(comment)