# app/modules/cms/routes/api/admin.py """ Admin Content Pages API Platform administrators can: - Create/edit/delete platform default content pages - View all vendor content pages - Override vendor content if needed """ import logging from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from app.api.deps import get_current_admin_api, get_db from app.exceptions import ValidationException from app.modules.cms.schemas import ( ContentPageCreate, ContentPageUpdate, ContentPageResponse, HomepageSectionsResponse, SectionUpdateResponse, ) from app.modules.cms.services import content_page_service from models.database.user import User # Route configuration for auto-discovery ROUTE_CONFIG = { "prefix": "/content-pages", "tags": ["admin-content-pages"], "priority": 100, # Register last (CMS has catch-all slug routes) } router = APIRouter() admin_router = router # Alias for discovery compatibility logger = logging.getLogger(__name__) # ============================================================================ # PLATFORM DEFAULT PAGES (vendor_id=NULL) # ============================================================================ @router.get("/platform", response_model=list[ContentPageResponse]) def list_platform_pages( include_unpublished: bool = Query(False, description="Include draft pages"), current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ List all platform default content pages. These are used as fallbacks when vendors haven't created custom pages. """ pages = content_page_service.list_all_platform_pages( db, include_unpublished=include_unpublished ) return [page.to_dict() for page in pages] @router.post("/platform", response_model=ContentPageResponse, status_code=201) def create_platform_page( page_data: ContentPageCreate, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ Create a new platform default content page. Platform defaults are shown to all vendors who haven't created their own version. """ # Force vendor_id to None for platform pages page = content_page_service.create_page( db, slug=page_data.slug, title=page_data.title, content=page_data.content, vendor_id=None, # Platform default content_format=page_data.content_format, template=page_data.template, meta_description=page_data.meta_description, meta_keywords=page_data.meta_keywords, is_published=page_data.is_published, show_in_footer=page_data.show_in_footer, show_in_header=page_data.show_in_header, show_in_legal=page_data.show_in_legal, display_order=page_data.display_order, created_by=current_user.id, ) db.commit() return page.to_dict() # ============================================================================ # VENDOR PAGES # ============================================================================ @router.post("/vendor", response_model=ContentPageResponse, status_code=201) def create_vendor_page( page_data: ContentPageCreate, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ Create a vendor-specific content page override. Vendor pages override platform defaults for a specific vendor. """ if not page_data.vendor_id: raise ValidationException( message="vendor_id is required for vendor pages. Use /platform for platform defaults.", field="vendor_id", ) page = content_page_service.create_page( db, slug=page_data.slug, title=page_data.title, content=page_data.content, vendor_id=page_data.vendor_id, content_format=page_data.content_format, template=page_data.template, meta_description=page_data.meta_description, meta_keywords=page_data.meta_keywords, is_published=page_data.is_published, show_in_footer=page_data.show_in_footer, show_in_header=page_data.show_in_header, show_in_legal=page_data.show_in_legal, display_order=page_data.display_order, created_by=current_user.id, ) db.commit() return page.to_dict() # ============================================================================ # ALL CONTENT PAGES (Platform + Vendors) # ============================================================================ @router.get("/", response_model=list[ContentPageResponse]) def list_all_pages( vendor_id: int | None = Query(None, description="Filter by vendor ID"), include_unpublished: bool = Query(False, description="Include draft pages"), current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ List all content pages (platform defaults and vendor overrides). Filter by vendor_id to see specific vendor pages. """ pages = content_page_service.list_all_pages( db, vendor_id=vendor_id, include_unpublished=include_unpublished ) return [page.to_dict() for page in pages] @router.get("/{page_id}", response_model=ContentPageResponse) def get_page( page_id: int, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """Get a specific content page by ID.""" page = content_page_service.get_page_by_id_or_raise(db, page_id) return page.to_dict() @router.put("/{page_id}", response_model=ContentPageResponse) def update_page( page_id: int, page_data: ContentPageUpdate, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """Update a content page (platform or vendor).""" page = content_page_service.update_page_or_raise( db, page_id=page_id, title=page_data.title, content=page_data.content, content_format=page_data.content_format, template=page_data.template, meta_description=page_data.meta_description, meta_keywords=page_data.meta_keywords, is_published=page_data.is_published, show_in_footer=page_data.show_in_footer, show_in_header=page_data.show_in_header, show_in_legal=page_data.show_in_legal, display_order=page_data.display_order, updated_by=current_user.id, ) db.commit() return page.to_dict() @router.delete("/{page_id}", status_code=204) def delete_page( page_id: int, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """Delete a content page.""" content_page_service.delete_page_or_raise(db, page_id) db.commit() # ============================================================================ # HOMEPAGE SECTIONS MANAGEMENT # ============================================================================ @router.get("/{page_id}/sections", response_model=HomepageSectionsResponse) def get_page_sections( page_id: int, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ Get homepage sections for a content page. Returns sections along with platform language settings for the editor. """ page = content_page_service.get_page_by_id_or_raise(db, page_id) # Get platform languages platform = page.platform supported_languages = ( platform.supported_languages if platform else ["fr", "de", "en"] ) default_language = platform.default_language if platform else "fr" return { "sections": page.sections, "supported_languages": supported_languages, "default_language": default_language, } @router.put("/{page_id}/sections", response_model=SectionUpdateResponse) def update_page_sections( page_id: int, sections: dict, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ Update all homepage sections at once. Expected structure: { "hero": { ... }, "features": { ... }, "pricing": { ... }, "cta": { ... } } """ page = content_page_service.update_homepage_sections( db, page_id=page_id, sections=sections, updated_by=current_user.id, ) db.commit() return { "message": "Sections updated successfully", "sections": page.sections, } @router.put("/{page_id}/sections/{section_name}", response_model=SectionUpdateResponse) def update_single_section( page_id: int, section_name: str, section_data: dict, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ Update a single section (hero, features, pricing, or cta). section_name must be one of: hero, features, pricing, cta """ if section_name not in ["hero", "features", "pricing", "cta"]: raise ValidationException( message=f"Invalid section name: {section_name}. Must be one of: hero, features, pricing, cta", field="section_name", ) page = content_page_service.update_single_section( db, page_id=page_id, section_name=section_name, section_data=section_data, updated_by=current_user.id, ) db.commit() return { "message": f"Section '{section_name}' updated successfully", "sections": page.sections, }