from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel, Field from sqlalchemy.orm import Session from app.core.deps import require_staff from app.db import get_db from app.models.home import ( admin_home_view, create_article, create_slide, delete_article, delete_slide, update_slide, save_audiences, save_compliance, save_contact, save_home, save_honors, save_hot_links, save_members, save_menu, save_related_links, set_article_display, update_article, ) router = APIRouter(dependencies=[Depends(require_staff)]) class TemplateWrite(BaseModel): name: str slogan: str = "" valueProposition: str = "" class HomeWrite(BaseModel): activeTemplate: str templates: list[TemplateWrite] = Field(min_length=2, max_length=2) class ArticleDisplayWrite(BaseModel): news: int | None = None notices: int | None = None policies: int | None = None dashboard: int | None = None class ArticleWrite(BaseModel): category: str title: str = "" publishedAt: str | None = None published: bool = False bodyHtml: str = "" imageFileId: int | None = None attachmentFileIds: list[int] = Field(default_factory=list) kind: str | None = None class AudienceLinkWrite(BaseModel): label: str url: str = "" visible: bool = True sortOrder: int = 0 class AudienceCategoryWrite(BaseModel): name: str links: list[AudienceLinkWrite] = Field(default_factory=list) class AudienceWrite(BaseModel): categories: list[AudienceCategoryWrite] = Field(min_length=3, max_length=3) class HotLinkWrite(BaseModel): key: str label: str url: str = "" visible: bool = True sortOrder: int = 0 class HotLinksWrite(BaseModel): links: list[HotLinkWrite] = Field(default_factory=list) class ContactWrite(BaseModel): name: str address: str = "" phone: str = "" email: str = "" latitude: float | None = None longitude: float | None = None class ContactBatchWrite(BaseModel): templates: list[ContactWrite] = Field(min_length=2, max_length=2) class RelatedLinkWrite(BaseModel): label: str url: str = "" visible: bool = True sortOrder: int = 0 class RelatedCategoryWrite(BaseModel): name: str links: list[RelatedLinkWrite] = Field(default_factory=list) class RelatedLinksWrite(BaseModel): templateName: str categories: list[RelatedCategoryWrite] = Field(min_length=3, max_length=3) class ComplianceWrite(BaseModel): templateName: str links: list[RelatedLinkWrite] = Field(default_factory=list) class HonorItemWrite(BaseModel): imageFileId: int sortOrder: int = 0 class HonorWrite(BaseModel): intervalSeconds: int = Field(gt=0) items: list[HonorItemWrite] = Field(default_factory=list) class MemberItemWrite(BaseModel): name: str url: str = "" imageFileId: int sortOrder: int = 0 class MemberWrite(BaseModel): intervalSeconds: int = Field(gt=0) items: list[MemberItemWrite] = Field(default_factory=list) class MenuItemWrite(BaseModel): key: str label: str url: str = "" visible: bool = False sortOrder: int = 0 class MenuWrite(BaseModel): items: list[MenuItemWrite] = Field(default_factory=list) class SlideWrite(BaseModel): title: str = "" imageFileId: int sortOrder: int = 0 enabled: bool = True intervalSeconds: int = Field(gt=0) published: bool = False bodyHtml: str = "" attachmentFileIds: list[int] = Field(default_factory=list) @router.get("/home") def read_home(db: Session = Depends(get_db)) -> dict: return admin_home_view(db) @router.put("/home") def write_home(body: HomeWrite, db: Session = Depends(get_db)) -> dict: try: save_home( db, body.activeTemplate, [item.model_dump() for item in body.templates], ) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/audiences") def write_audiences(body: AudienceWrite, db: Session = Depends(get_db)) -> dict: try: save_audiences(db, [item.model_dump() for item in body.categories]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/hot-links") def write_hot_links(body: HotLinksWrite, db: Session = Depends(get_db)) -> dict: try: save_hot_links(db, [item.model_dump() for item in body.links]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/contact") def write_contact(body: ContactBatchWrite, db: Session = Depends(get_db)) -> dict: try: save_contact(db, [item.model_dump() for item in body.templates]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/related-links") def write_related_links(body: RelatedLinksWrite, db: Session = Depends(get_db)) -> dict: try: save_related_links( db, body.templateName, [item.model_dump() for item in body.categories], ) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/compliance") def write_compliance(body: ComplianceWrite, db: Session = Depends(get_db)) -> dict: try: save_compliance(db, body.templateName, [item.model_dump() for item in body.links]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/honors") def write_honors(body: HonorWrite, db: Session = Depends(get_db)) -> dict: try: save_honors(db, body.intervalSeconds, [item.model_dump() for item in body.items]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/members") def write_members(body: MemberWrite, db: Session = Depends(get_db)) -> dict: try: save_members(db, body.intervalSeconds, [item.model_dump() for item in body.items]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/menu") def write_menu(body: MenuWrite, db: Session = Depends(get_db)) -> dict: try: save_menu(db, [item.model_dump() for item in body.items]) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.put("/home/articles/display") def write_article_display(body: ArticleDisplayWrite, db: Session = Depends(get_db)) -> dict: try: set_article_display(db, body.model_dump(exclude_unset=True)) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"ok": True} @router.post("/home/articles") def write_article(body: ArticleWrite, db: Session = Depends(get_db)) -> dict: try: article_id = create_article(db, body.model_dump()) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"id": article_id} @router.put("/home/articles/{article_id}") def revise_article(article_id: int, body: ArticleWrite, db: Session = Depends(get_db)) -> dict: try: update_article(db, article_id, body.model_dump()) except ValueError as exc: code = status.HTTP_404_NOT_FOUND if str(exc) == "文章不存在" else status.HTTP_400_BAD_REQUEST raise HTTPException(status_code=code, detail=str(exc)) from exc return {"ok": True} @router.delete("/home/articles/{article_id}") def remove_article(article_id: int, db: Session = Depends(get_db)) -> dict: try: delete_article(db, article_id) except ValueError as exc: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc return {"ok": True} @router.post("/home/slides") def write_slide(body: SlideWrite, db: Session = Depends(get_db)) -> dict: try: slide_id = create_slide(db, body.model_dump()) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"id": slide_id} @router.put("/home/slides/{slide_id}") def revise_slide(slide_id: int, body: SlideWrite, db: Session = Depends(get_db)) -> dict: try: update_slide(db, slide_id, body.model_dump()) except ValueError as exc: code = status.HTTP_404_NOT_FOUND if str(exc) == "轮播不存在" else status.HTTP_400_BAD_REQUEST raise HTTPException(status_code=code, detail=str(exc)) from exc return {"ok": True} @router.delete("/home/slides/{slide_id}") def remove_slide(slide_id: int, db: Session = Depends(get_db)) -> dict: try: delete_slide(db, slide_id) except ValueError as exc: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc return {"ok": True}