# 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 typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, 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") meta_description: Optional[str] = Field(None, max_length=300, description="SEO meta description") meta_keywords: Optional[str] = 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: Optional[int] = Field(None, description="Vendor ID (None for platform default)") class ContentPageUpdate(BaseModel): """Schema for updating a content page.""" title: Optional[str] = Field(None, max_length=200) content: Optional[str] = None content_format: Optional[str] = None meta_description: Optional[str] = Field(None, max_length=300) meta_keywords: Optional[str] = Field(None, max_length=300) is_published: Optional[bool] = None show_in_footer: Optional[bool] = None show_in_header: Optional[bool] = None display_order: Optional[int] = None class ContentPageResponse(BaseModel): """Schema for content page response.""" id: int vendor_id: Optional[int] vendor_name: Optional[str] slug: str title: str content: str content_format: str meta_description: Optional[str] meta_keywords: Optional[str] is_published: bool published_at: Optional[str] 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: Optional[int] updated_by: Optional[int] # ============================================================================ # 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, 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 ) return page.to_dict() # ============================================================================ # ALL CONTENT PAGES (Platform + Vendors) # ============================================================================ @router.get("/", response_model=List[ContentPageResponse]) def list_all_pages( vendor_id: Optional[int] = 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. """ if vendor_id: pages = content_page_service.list_all_vendor_pages( db, vendor_id=vendor_id, include_unpublished=include_unpublished ) else: # Get all pages (both platform and vendor) from models.database.content_page import ContentPage from sqlalchemy import and_ filters = [] if not include_unpublished: filters.append(ContentPage.is_published == True) pages = ( db.query(ContentPage) .filter(and_(*filters) if filters else True) .order_by(ContentPage.vendor_id, ContentPage.display_order, ContentPage.title) .all() ) 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(db, page_id) if not page: raise HTTPException(status_code=404, detail="Content page not found") 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( db, page_id=page_id, title=page_data.title, content=page_data.content, content_format=page_data.content_format, 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 ) if not page: raise HTTPException(status_code=404, detail="Content page not found") 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.""" success = content_page_service.delete_page(db, page_id) if not success: raise HTTPException(status_code=404, detail="Content page not found") return None