from __future__ import annotations from typing import Annotated from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status from app.api.deps import require_student from app.core.database import get_connection from app.core.ratelimit import check_diagnosis_rate_limit from app.core.schemas import ( DiagnosisAnswerRequest, DiagnosisResponse, DiagnosisStartRequest, FeedbackRequest, OrderCreateRequest, OrderDetailOut, OrderSummaryOut, ReworkRequest, SavedAddressOut, UserProfile, ) from app.services import repository from app.services.diagnosis import get_diagnosis_provider router = APIRouter(prefix="/api/student", tags=["student"]) @router.post("/diagnosis/start", response_model=DiagnosisResponse) async def start_diagnosis( payload: DiagnosisStartRequest, _: Annotated[UserProfile, Depends(require_student)], _rl: None = Depends(check_diagnosis_rate_limit), ) -> DiagnosisResponse: provider = get_diagnosis_provider() return await provider.start(payload.message) @router.post("/diagnosis/answer", response_model=DiagnosisResponse) async def answer_diagnosis( payload: DiagnosisAnswerRequest, _: Annotated[UserProfile, Depends(require_student)], _rl: None = Depends(check_diagnosis_rate_limit), ) -> DiagnosisResponse: try: provider = get_diagnosis_provider() return await provider.answer(payload.session_id, payload.answers) except KeyError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error.args[0]) from error @router.get("/addresses", response_model=list[SavedAddressOut]) def list_addresses(user: Annotated[UserProfile, Depends(require_student)]) -> list[dict[str, object]]: with get_connection() as connection: return repository.list_addresses(connection, user.id) @router.delete("/addresses/{address_id}") def delete_address(address_id: int, user: Annotated[UserProfile, Depends(require_student)]) -> dict[str, str]: with get_connection() as connection: if not repository.delete_address(connection, address_id, user.id): raise HTTPException(status_code=404, detail="地址不存在") return {"message": "已删除"} @router.post("/orders") def create_order(payload: OrderCreateRequest, user: Annotated[UserProfile, Depends(require_student)]) -> dict[str, int]: with get_connection() as connection: order_id = repository.create_order(connection, user, payload) return {"order_id": order_id} @router.post("/orders/{order_id}/attachments") def upload_attachments( order_id: int, user: Annotated[UserProfile, Depends(require_student)], files: Annotated[list[UploadFile], File(...)], ) -> dict[str, str]: with get_connection() as connection: order = repository.get_order_detail(connection, order_id, student_id=user.id) if order is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="order_not_found") for file in files: try: repository.save_attachment(connection, order_id, file) except ValueError as error: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(error)) from error return {"status": "ok"} @router.post("/orders/{order_id}/cancel") def cancel_order( order_id: int, user: Annotated[UserProfile, Depends(require_student)], ) -> dict[str, str]: with get_connection() as connection: try: repository.cancel_order(connection, order_id, user) except KeyError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error.args[0]) from error except ValueError as error: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=error.args[0]) from error return {"status": "ok"} @router.get("/orders", response_model=list[OrderSummaryOut]) def list_orders(user: Annotated[UserProfile, Depends(require_student)]) -> list[dict[str, str]]: with get_connection() as connection: return repository.list_orders(connection, student_id=user.id) @router.get("/orders/{order_id}", response_model=OrderDetailOut) def get_order(order_id: int, user: Annotated[UserProfile, Depends(require_student)]) -> dict[str, str]: with get_connection() as connection: detail = repository.get_order_detail(connection, order_id, student_id=user.id) if detail is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="order_not_found") return detail @router.post("/orders/{order_id}/confirm") def confirm_order(order_id: int, user: Annotated[UserProfile, Depends(require_student)]) -> dict[str, str]: with get_connection() as connection: try: repository.confirm_order(connection, order_id, user) except KeyError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error.args[0]) from error except ValueError as error: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=error.args[0]) from error return {"status": "ok"} @router.post("/orders/{order_id}/feedback") def submit_feedback( order_id: int, payload: FeedbackRequest, user: Annotated[UserProfile, Depends(require_student)], ) -> dict[str, str]: with get_connection() as connection: try: repository.add_feedback(connection, order_id, user, payload) except KeyError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error.args[0]) from error except ValueError as error: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=error.args[0]) from error return {"status": "ok"} @router.post("/orders/{order_id}/rework") def submit_rework( order_id: int, payload: ReworkRequest, user: Annotated[UserProfile, Depends(require_student)], ) -> dict[str, str]: with get_connection() as connection: try: repository.request_rework(connection, order_id, user, payload) except KeyError as error: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error.args[0]) from error except ValueError as error: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=error.args[0]) from error return {"status": "ok"}