from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile from sqlalchemy.orm import Session, joinedload from app.auth import get_current_admin from app.database import get_db from app.models import AdminUser, EventEdition, MediaAsset, PlatformLink from app.schemas import ( EventEditionCreate, EventEditionAdmin, EventEditionUpdate, MediaReorderItem, PlatformLinkCreate, PlatformLinkPublic, PlatformLinkUpdate, ) from app.services.editions import edition_to_admin, edition_to_public from app.services.media import public_url_for_path, save_image router = APIRouter(prefix="/api/admin", tags=["admin"]) @router.get("/me") def me(admin: AdminUser = Depends(get_current_admin)): return {"email": admin.email, "role": admin.role.value} # --- Platform links --- @router.get("/links", response_model=list[PlatformLinkPublic]) def list_links(db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin)): rows = db.query(PlatformLink).order_by(PlatformLink.sort_order, PlatformLink.id).all() return [PlatformLinkPublic.model_validate(r) for r in rows] @router.post("/links", response_model=PlatformLinkPublic) def create_link( body: PlatformLinkCreate, db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): row = PlatformLink(**body.model_dump()) db.add(row) db.commit() db.refresh(row) return PlatformLinkPublic.model_validate(row) @router.patch("/links/{link_id}", response_model=PlatformLinkPublic) def update_link( link_id: int, body: PlatformLinkUpdate, db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): row = db.query(PlatformLink).filter(PlatformLink.id == link_id).first() if not row: raise HTTPException(status_code=404, detail="Link not found") for k, v in body.model_dump(exclude_unset=True).items(): setattr(row, k, v) db.commit() db.refresh(row) return PlatformLinkPublic.model_validate(row) @router.delete("/links/{link_id}") def delete_link(link_id: int, db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin)): row = db.query(PlatformLink).filter(PlatformLink.id == link_id).first() if not row: raise HTTPException(status_code=404, detail="Link not found") db.delete(row) db.commit() return {"ok": True} # --- Editions --- @router.get("/editions", response_model=list[EventEditionAdmin]) def admin_list_editions(db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin)): editions = ( db.query(EventEdition) .options(joinedload(EventEdition.media)) .order_by(EventEdition.id.desc()) .all() ) return [edition_to_admin(e) for e in editions] @router.post("/editions", response_model=EventEditionAdmin) def create_edition( body: EventEditionCreate, db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): if db.query(EventEdition).filter(EventEdition.slug == body.slug).first(): raise HTTPException(status_code=400, detail="Slug already exists") edition = EventEdition(city="Bengaluru", **body.model_dump()) db.add(edition) db.commit() db.refresh(edition) edition = ( db.query(EventEdition) .options(joinedload(EventEdition.media)) .filter(EventEdition.id == edition.id) .one() ) return edition_to_admin(edition) @router.patch("/editions/{edition_id}", response_model=EventEditionAdmin) def update_edition( edition_id: int, body: EventEditionUpdate, db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): edition = db.query(EventEdition).filter(EventEdition.id == edition_id).first() if not edition: raise HTTPException(status_code=404, detail="Edition not found") data = body.model_dump(exclude_unset=True) if "slug" in data and data["slug"] != edition.slug: if db.query(EventEdition).filter(EventEdition.slug == data["slug"]).first(): raise HTTPException(status_code=400, detail="Slug already exists") for k, v in data.items(): setattr(edition, k, v) db.commit() edition = ( db.query(EventEdition) .options(joinedload(EventEdition.media)) .filter(EventEdition.id == edition_id) .one() ) return edition_to_admin(edition) @router.post("/editions/{edition_id}/cover") async def upload_cover( edition_id: int, file: UploadFile = File(...), db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): edition = db.query(EventEdition).filter(EventEdition.id == edition_id).first() if not edition: raise HTTPException(status_code=404, detail="Edition not found") try: path = save_image(file) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) edition.cover_image_path = path db.commit() return {"cover_image_url": public_url_for_path(path)} @router.post("/editions/{edition_id}/media") async def upload_media( edition_id: int, file: UploadFile = File(...), caption: str | None = Form(default=None), sort_order: int = Form(default=0), db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): edition = db.query(EventEdition).filter(EventEdition.id == edition_id).first() if not edition: raise HTTPException(status_code=404, detail="Edition not found") try: path = save_image(file) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) asset = MediaAsset( edition_id=edition_id, file_path=path, caption=caption, sort_order=sort_order, is_published=True, ) db.add(asset) db.commit() db.refresh(asset) return { "id": asset.id, "url": public_url_for_path(path), "caption": asset.caption, "sort_order": asset.sort_order, } @router.patch("/media/{media_id}") def update_media( media_id: int, caption: str | None = Form(default=None), sort_order: int | None = Form(default=None), is_published: bool | None = Form(default=None), db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): asset = db.query(MediaAsset).filter(MediaAsset.id == media_id).first() if not asset: raise HTTPException(status_code=404, detail="Media not found") if caption is not None: asset.caption = caption if sort_order is not None: asset.sort_order = sort_order if is_published is not None: asset.is_published = is_published db.commit() return {"ok": True} @router.post("/editions/{edition_id}/media/reorder") def reorder_media( edition_id: int, items: list[MediaReorderItem], db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin), ): for item in items: asset = ( db.query(MediaAsset) .filter(MediaAsset.id == item.id, MediaAsset.edition_id == edition_id) .first() ) if asset: asset.sort_order = item.sort_order db.commit() return {"ok": True} @router.delete("/media/{media_id}") def delete_media(media_id: int, db: Session = Depends(get_db), _: AdminUser = Depends(get_current_admin)): asset = db.query(MediaAsset).filter(MediaAsset.id == media_id).first() if not asset: raise HTTPException(status_code=404, detail="Media not found") db.delete(asset) db.commit() return {"ok": True}