Files
orion/app/modules/cms/routes/api/storefront.py
Samir Boulahtit 32acc76b49 feat: platform-aware storefront routing and billing improvements
Overhaul storefront URL routing to be platform-aware:
- Dev: /platforms/{code}/storefront/{store_code}/
- Prod: subdomain.platform.lu/ (internally rewritten to /storefront/)
- Add subdomain detection in PlatformContextMiddleware
- Add /storefront/ path rewrite for prod mode (subdomain/custom domain)
- Remove all silent platform fallbacks (platform_id=1)
- Add require_platform dependency for clean endpoint validation
- Update route registration, templates, module definitions, base_url calc
- Update StoreContextMiddleware for /storefront/ path detection
- Remove /stores/ from FrontendDetector STOREFRONT_PATH_PREFIXES

Billing service improvements:
- Add store_platform_sync_service to keep store_platforms in sync
- Make tier lookups platform-aware across billing services
- Add tiers for all platforms in seed data
- Add demo subscriptions to seed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:42:41 +01:00

99 lines
2.8 KiB
Python

# app/modules/cms/routes/api/storefront.py
"""
Storefront Content Pages API (Public)
Public endpoints for retrieving content pages in storefront.
No authentication required.
"""
import logging
from fastapi import APIRouter, Depends, Request
from sqlalchemy.orm import Session
from app.api.deps import require_platform
from app.core.database import get_db
from app.modules.cms.schemas import (
ContentPageListItem,
PublicContentPageResponse,
)
from app.modules.cms.services import content_page_service
router = APIRouter()
logger = logging.getLogger(__name__)
# ============================================================================
# PUBLIC ENDPOINTS
# ============================================================================
# public - storefront content pages are publicly accessible
@router.get("/navigation", response_model=list[ContentPageListItem])
def get_navigation_pages(
request: Request,
platform=Depends(require_platform),
db: Session = Depends(get_db),
):
"""
Get list of content pages for navigation (footer/header).
Uses store from request.state (set by middleware).
Returns store overrides + platform defaults.
"""
store = getattr(request.state, "store", None)
store_id = store.id if store else None
platform_id = platform.id
# Get all published pages for this store
pages = content_page_service.list_pages_for_store(
db, platform_id=platform_id, store_id=store_id, include_unpublished=False
)
return [
{
"slug": page.slug,
"title": page.title,
"show_in_footer": page.show_in_footer,
"show_in_header": page.show_in_header,
"display_order": page.display_order,
}
for page in pages
]
@router.get("/{slug}", response_model=PublicContentPageResponse)
def get_content_page(
slug: str,
request: Request,
platform=Depends(require_platform),
db: Session = Depends(get_db),
):
"""
Get a specific content page by slug.
Uses store from request.state (set by middleware).
Returns store override if exists, otherwise platform default.
"""
store = getattr(request.state, "store", None)
store_id = store.id if store else None
platform_id = platform.id
page = content_page_service.get_page_for_store_or_raise(
db,
platform_id=platform_id,
slug=slug,
store_id=store_id,
include_unpublished=False, # Only show published pages
)
return {
"slug": page.slug,
"title": page.title,
"content": page.content,
"content_format": page.content_format,
"meta_description": page.meta_description,
"meta_keywords": page.meta_keywords,
"published_at": page.published_at.isoformat() if page.published_at else None,
}