Files
orion/app/api/v1/admin/content_pages.py
Samir Boulahtit c1ff0a00db fix: correct authentication dependency names in CMS API endpoints
Fix ImportError by using correct authentication dependency names:
- Use get_current_admin_api instead of get_current_admin_user
- Use get_current_vendor_api instead of get_current_vendor_user

These are the correct dependency names for API endpoints that require
Authorization header authentication (no cookie support).

Fixes: ImportError: cannot import name 'get_current_admin_user'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 15:59:15 +01:00

233 lines
7.7 KiB
Python

# 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