from fastapi import APIRouter, Depends, status from pydantic import BaseModel, Field, field_validator from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.api.timeutil import isoformat_utc from app.auth.dependencies import get_current_user, get_optional_user from app.db.models import BugReport, User from app.db.session import get_session router = APIRouter(prefix="/bug-reports", tags=["bug-reports"]) class BugReportCreate(BaseModel): description: str = Field(min_length=1, max_length=2000) contact: str | None = Field(default=None, max_length=256) @field_validator("description") @classmethod def _description_not_blank(cls, value: str) -> str: value = value.strip() if not value: raise ValueError("description must not be blank") return value @field_validator("contact") @classmethod def _contact_stripped(cls, value: str | None) -> str | None: if value is None: return None value = value.strip() return value or None class BugReportResponse(BaseModel): id: int @router.post("", response_model=BugReportResponse, status_code=status.HTTP_201_CREATED) async def create_bug_report( body: BugReportCreate, user: User | None = Depends(get_optional_user), session: AsyncSession = Depends(get_session), ) -> BugReportResponse: report = BugReport( description=body.description, contact=body.contact, user_id=user.id if user is not None else None, ) session.add(report) await session.commit() return BugReportResponse(id=report.id) class MyBugReportResponse(BaseModel): id: int description: str status: str created_at: str @router.get("/mine", response_model=list[MyBugReportResponse]) async def list_my_bug_reports( user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session), ) -> list[MyBugReportResponse]: """The one user-facing history view for bug reports (anonymous submissions have no user to attribute this to, so this only ever covers ones filed while logged in).""" reports = ( await session.scalars( select(BugReport).where(BugReport.user_id == user.id).order_by(BugReport.id.desc()) ) ).all() return [ MyBugReportResponse( id=r.id, description=r.description, status=r.status, created_at=isoformat_utc(r.created_at) ) for r in reports ]