# app/api/v1/admin/content_pages.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 pydantic import BaseModel, Field from sqlalchemy.orm import Session from app.api.deps import get_current_admin_api, get_db from app.services.content_page_service import content_page_service from models.database.user import User router = APIRouter() logger = logging.getLogger(__name__) # ============================================================================ # REQUEST/RESPONSE SCHEMAS # ============================================================================ class ContentPageCreate(BaseModel): """Schema for creating a content page.""" slug: str = Field( ..., max_length=100, description="URL-safe identifier (about, faq, contact, etc.)", ) title: str = Field(..., max_length=200, description="Page title") content: str = Field(..., description="HTML or Markdown content") content_format: str = Field( default="html", description="Content format: html or markdown" ) template: str = Field( default="default", max_length=50, description="Template name (default, minimal, modern)", ) meta_description: str | None = Field( None, max_length=300, description="SEO meta description" ) meta_keywords: str | None = Field(None, max_length=300, description="SEO keywords") is_published: bool = Field(default=False, description="Publish immediately") show_in_footer: bool = Field(default=True, description="Show in footer navigation") show_in_header: bool = Field(default=False, description="Show in header navigation") display_order: int = Field(default=0, description="Display order (lower = first)") vendor_id: int | None = Field( None, description="Vendor ID (None for platform default)" ) class ContentPageUpdate(BaseModel): """Schema for updating a content page.""" title: str | None = Field(None, max_length=200) content: str | None = None content_format: str | None = None template: str | None = Field(None, max_length=50) meta_description: str | None = Field(None, max_length=300) meta_keywords: str | None = Field(None, max_length=300) is_published: bool | None = None show_in_footer: bool | None = None show_in_header: bool | None = None display_order: int | None = None class ContentPageResponse(BaseModel): """Schema for content page response.""" id: int vendor_id: int | None vendor_name: str | None slug: str title: str content: str content_format: str meta_description: str | None meta_keywords: str | None is_published: bool published_at: str | None display_order: int show_in_footer: bool show_in_header: bool is_platform_default: bool is_vendor_override: bool created_at: str updated_at: str created_by: int | None updated_by: int | None # ============================================================================ # 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, 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, 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()