# app/modules/cms/routes/api/admin_content_pages.py """ Admin Content Pages API Platform administrators can: - Create/edit/delete platform default content pages - View all store content pages - Override store 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, ContentPageResponse, ContentPageUpdate, HomepageSectionsResponse, SectionUpdateResponse, ) from app.modules.cms.services import content_page_service from app.modules.tenancy.models import User admin_content_pages_router = APIRouter(prefix="/content-pages") logger = logging.getLogger(__name__) # ============================================================================ # PLATFORM DEFAULT PAGES (store_id=NULL) # ============================================================================ @admin_content_pages_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 stores 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] @admin_content_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 stores who haven't created their own version. """ # Force store_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, store_id=None, # Platform default content_format=page_data.content_format, template=page_data.template, meta_description=page_data.meta_description, meta_description_translations=page_data.meta_description_translations, 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() # ============================================================================ # STORE PAGES # ============================================================================ @admin_content_pages_router.post("/store", response_model=ContentPageResponse, status_code=201) def create_store_page( page_data: ContentPageCreate, current_user: User = Depends(get_current_admin_api), db: Session = Depends(get_db), ): """ Create a store-specific content page override. Store pages override platform defaults for a specific store. """ if not page_data.store_id: raise ValidationException( message="store_id is required for store pages. Use /platform for platform defaults.", field="store_id", ) page = content_page_service.create_page( db, slug=page_data.slug, title=page_data.title, content=page_data.content, store_id=page_data.store_id, content_format=page_data.content_format, template=page_data.template, meta_description=page_data.meta_description, meta_description_translations=page_data.meta_description_translations, 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 + Stores) # ============================================================================ @admin_content_pages_router.get("/", response_model=list[ContentPageResponse]) def list_all_pages( store_id: int | None = Query(None, description="Filter by store 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 store overrides). Filter by store_id to see specific store pages. """ pages = content_page_service.list_all_pages( db, store_id=store_id, include_unpublished=include_unpublished ) return [page.to_dict() for page in pages] @admin_content_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() @admin_content_pages_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 store).""" page = content_page_service.update_page_or_raise( db, page_id=page_id, title=page_data.title, title_translations=page_data.title_translations, content=page_data.content, content_translations=page_data.content_translations, content_format=page_data.content_format, template=page_data.template, meta_description=page_data.meta_description, meta_description_translations=page_data.meta_description_translations, 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() @admin_content_pages_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 # ============================================================================ @admin_content_pages_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, } @admin_content_pages_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, } @admin_content_pages_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, }