feat: integrate PlatformContextMiddleware and update routes for multi-platform
Phase 2 implementation: - Register PlatformContextMiddleware in main.py (runs before VendorContextMiddleware) - Update VendorContextMiddleware to use platform_clean_path - Update platform homepage route to use three-tier CMS resolution - Update platform content page routes with platform context - Update vendor root path handlers with platform_id support Middleware execution order: 1. LoggingMiddleware 2. PlatformContextMiddleware (detect platform from domain/path) 3. VendorContextMiddleware (detect vendor, uses platform_clean_path) 4. ContextMiddleware 5. LanguageMiddleware 6. ThemeContextMiddleware Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
133
main.py
133
main.py
@@ -70,6 +70,7 @@ from middleware.logging import LoggingMiddleware
|
||||
from middleware.theme_context import ThemeContextMiddleware
|
||||
|
||||
# Import REFACTORED class-based middleware
|
||||
from middleware.platform_context import PlatformContextMiddleware
|
||||
from middleware.vendor_context import VendorContextMiddleware
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -114,17 +115,19 @@ app.add_middleware(
|
||||
# So we add them in REVERSE order of desired execution:
|
||||
#
|
||||
# Desired execution order:
|
||||
# 1. VendorContextMiddleware (detect vendor, extract clean_path)
|
||||
# 2. ContextMiddleware (detect context using clean_path)
|
||||
# 3. LanguageMiddleware (detect language based on context)
|
||||
# 4. ThemeContextMiddleware (load theme)
|
||||
# 5. LoggingMiddleware (log all requests)
|
||||
# 1. PlatformContextMiddleware (detect platform from domain/path)
|
||||
# 2. VendorContextMiddleware (detect vendor, uses platform_clean_path)
|
||||
# 3. ContextMiddleware (detect context using clean_path)
|
||||
# 4. LanguageMiddleware (detect language based on context)
|
||||
# 5. ThemeContextMiddleware (load theme)
|
||||
# 6. LoggingMiddleware (log all requests)
|
||||
#
|
||||
# Therefore we add them in REVERSE:
|
||||
# - Add ThemeContextMiddleware FIRST (runs LAST in request)
|
||||
# - Add LanguageMiddleware SECOND (runs after context)
|
||||
# - Add LanguageMiddleware SECOND
|
||||
# - Add ContextMiddleware THIRD
|
||||
# - Add VendorContextMiddleware FOURTH
|
||||
# - Add PlatformContextMiddleware FIFTH
|
||||
# - Add LoggingMiddleware LAST (runs FIRST for timing)
|
||||
# ============================================================================
|
||||
|
||||
@@ -148,19 +151,24 @@ app.add_middleware(LanguageMiddleware)
|
||||
logger.info("Adding ContextMiddleware (detects context type using clean_path)")
|
||||
app.add_middleware(ContextMiddleware)
|
||||
|
||||
# Add vendor context middleware (runs first in request chain)
|
||||
logger.info("Adding VendorContextMiddleware (detects vendor, extracts clean_path)")
|
||||
# Add vendor context middleware (runs after platform context)
|
||||
logger.info("Adding VendorContextMiddleware (detects vendor, uses platform_clean_path)")
|
||||
app.add_middleware(VendorContextMiddleware)
|
||||
|
||||
# Add platform context middleware (runs first in request chain, before vendor)
|
||||
logger.info("Adding PlatformContextMiddleware (detects platform from domain/path)")
|
||||
app.add_middleware(PlatformContextMiddleware)
|
||||
|
||||
logger.info("=" * 80)
|
||||
logger.info("MIDDLEWARE ORDER SUMMARY:")
|
||||
logger.info(" Execution order (request →):")
|
||||
logger.info(" 1. LoggingMiddleware (timing)")
|
||||
logger.info(" 2. VendorContextMiddleware (vendor detection)")
|
||||
logger.info(" 3. ContextMiddleware (context detection)")
|
||||
logger.info(" 4. LanguageMiddleware (language detection)")
|
||||
logger.info(" 5. ThemeContextMiddleware (theme loading)")
|
||||
logger.info(" 6. FastAPI Router")
|
||||
logger.info(" 2. PlatformContextMiddleware (platform detection)")
|
||||
logger.info(" 3. VendorContextMiddleware (vendor detection)")
|
||||
logger.info(" 4. ContextMiddleware (context detection)")
|
||||
logger.info(" 5. LanguageMiddleware (language detection)")
|
||||
logger.info(" 6. ThemeContextMiddleware (theme loading)")
|
||||
logger.info(" 7. FastAPI Router")
|
||||
logger.info("=" * 80)
|
||||
|
||||
# ========================================
|
||||
@@ -331,6 +339,7 @@ async def vendor_root_path(
|
||||
"""Handle vendor root path (e.g., /vendors/wizamart/)"""
|
||||
# Vendor should already be in request.state from middleware
|
||||
vendor = getattr(request.state, "vendor", None)
|
||||
platform = getattr(request.state, "platform", None)
|
||||
|
||||
if not vendor:
|
||||
raise HTTPException(status_code=404, detail=f"Vendor '{vendor_code}' not found")
|
||||
@@ -338,14 +347,17 @@ async def vendor_root_path(
|
||||
from app.routes.shop_pages import get_shop_context
|
||||
from app.services.content_page_service import content_page_service
|
||||
|
||||
# Try to find landing page
|
||||
# Get platform_id (use platform from context or default to 1 for OMS)
|
||||
platform_id = platform.id if platform else 1
|
||||
|
||||
# Try to find landing page (with three-tier resolution)
|
||||
landing_page = content_page_service.get_page_for_vendor(
|
||||
db, slug="landing", vendor_id=vendor.id, include_unpublished=False
|
||||
db, platform_id=platform_id, slug="landing", vendor_id=vendor.id, include_unpublished=False
|
||||
)
|
||||
|
||||
if not landing_page:
|
||||
landing_page = content_page_service.get_page_for_vendor(
|
||||
db, slug="home", vendor_id=vendor.id, include_unpublished=False
|
||||
db, platform_id=platform_id, slug="home", vendor_id=vendor.id, include_unpublished=False
|
||||
)
|
||||
|
||||
if landing_page:
|
||||
@@ -373,29 +385,51 @@ async def platform_homepage(request: Request, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Platform homepage at localhost:8000 or platform.com
|
||||
|
||||
Looks for CMS page with slug='platform_homepage' (vendor_id=NULL)
|
||||
Uses multi-platform CMS with three-tier resolution:
|
||||
1. Platform marketing pages (is_platform_page=True)
|
||||
2. Vendor default pages (fallback)
|
||||
3. Vendor override pages
|
||||
|
||||
Falls back to default static template if not found.
|
||||
"""
|
||||
from app.services.content_page_service import content_page_service
|
||||
|
||||
logger.debug("[PLATFORM] Homepage requested")
|
||||
|
||||
# Try to load platform homepage from CMS
|
||||
homepage = content_page_service.get_page_for_vendor(
|
||||
db,
|
||||
slug="platform_homepage",
|
||||
vendor_id=None, # Platform-level page
|
||||
include_unpublished=False,
|
||||
)
|
||||
# Get platform from middleware (multi-platform support)
|
||||
platform = getattr(request.state, "platform", None)
|
||||
|
||||
# Load header and footer navigation
|
||||
header_pages = content_page_service.list_pages_for_vendor(
|
||||
db, vendor_id=None, header_only=True, include_unpublished=False
|
||||
)
|
||||
if platform:
|
||||
# Try to load platform homepage from CMS (platform marketing page)
|
||||
homepage = content_page_service.get_platform_page(
|
||||
db,
|
||||
platform_id=platform.id,
|
||||
slug="home",
|
||||
include_unpublished=False,
|
||||
)
|
||||
|
||||
footer_pages = content_page_service.list_pages_for_vendor(
|
||||
db, vendor_id=None, footer_only=True, include_unpublished=False
|
||||
)
|
||||
# Also try platform_homepage slug for backwards compatibility
|
||||
if not homepage:
|
||||
homepage = content_page_service.get_platform_page(
|
||||
db,
|
||||
platform_id=platform.id,
|
||||
slug="platform_homepage",
|
||||
include_unpublished=False,
|
||||
)
|
||||
|
||||
# Load header and footer navigation (platform marketing pages)
|
||||
header_pages = content_page_service.list_platform_pages(
|
||||
db, platform_id=platform.id, header_only=True, include_unpublished=False
|
||||
)
|
||||
|
||||
footer_pages = content_page_service.list_platform_pages(
|
||||
db, platform_id=platform.id, footer_only=True, include_unpublished=False
|
||||
)
|
||||
else:
|
||||
# Fallback for when no platform context (shouldn't happen normally)
|
||||
homepage = None
|
||||
header_pages = []
|
||||
footer_pages = []
|
||||
|
||||
# Get language from request state and build i18n context
|
||||
language = getattr(request.state, "language", "fr")
|
||||
@@ -438,7 +472,7 @@ async def platform_content_page(
|
||||
"""
|
||||
Platform content pages: /about, /faq, /terms, /contact, etc.
|
||||
|
||||
Loads content from CMS with slug (vendor_id=NULL for platform pages).
|
||||
Uses multi-platform CMS with three-tier resolution.
|
||||
Returns 404 if page not found.
|
||||
|
||||
This route MUST be defined LAST to avoid conflicts with other routes.
|
||||
@@ -447,25 +481,32 @@ async def platform_content_page(
|
||||
|
||||
logger.debug(f"[PLATFORM] Content page requested: /{slug}")
|
||||
|
||||
# Load page from CMS
|
||||
page = content_page_service.get_page_for_vendor(
|
||||
# Get platform from middleware (multi-platform support)
|
||||
platform = getattr(request.state, "platform", None)
|
||||
|
||||
if not platform:
|
||||
logger.warning(f"[PLATFORM] No platform context for content page: {slug}")
|
||||
raise HTTPException(status_code=404, detail=f"Page not found: {slug}")
|
||||
|
||||
# Load platform marketing page from CMS
|
||||
page = content_page_service.get_platform_page(
|
||||
db,
|
||||
platform_id=platform.id,
|
||||
slug=slug,
|
||||
vendor_id=None,
|
||||
include_unpublished=False, # Platform pages only
|
||||
include_unpublished=False,
|
||||
)
|
||||
|
||||
if not page:
|
||||
logger.warning(f"[PLATFORM] Content page not found: {slug}")
|
||||
raise HTTPException(status_code=404, detail=f"Page not found: {slug}")
|
||||
|
||||
# Load header and footer navigation
|
||||
header_pages = content_page_service.list_pages_for_vendor(
|
||||
db, vendor_id=None, header_only=True, include_unpublished=False
|
||||
# Load header and footer navigation (platform marketing pages)
|
||||
header_pages = content_page_service.list_platform_pages(
|
||||
db, platform_id=platform.id, header_only=True, include_unpublished=False
|
||||
)
|
||||
|
||||
footer_pages = content_page_service.list_pages_for_vendor(
|
||||
db, vendor_id=None, footer_only=True, include_unpublished=False
|
||||
footer_pages = content_page_service.list_platform_pages(
|
||||
db, platform_id=platform.id, footer_only=True, include_unpublished=False
|
||||
)
|
||||
|
||||
logger.info(f"[PLATFORM] Rendering content page: {page.title} (/{slug})")
|
||||
@@ -511,20 +552,24 @@ async def root(request: Request, db: Session = Depends(get_db)):
|
||||
- If no vendor (platform root): Redirect to documentation
|
||||
"""
|
||||
vendor = getattr(request.state, "vendor", None)
|
||||
platform = getattr(request.state, "platform", None)
|
||||
|
||||
if vendor:
|
||||
# Vendor context detected - serve landing page
|
||||
from app.services.content_page_service import content_page_service
|
||||
|
||||
# Try to find landing page (slug='landing' or 'home')
|
||||
# Get platform_id (use platform from context or default to 1 for OMS)
|
||||
platform_id = platform.id if platform else 1
|
||||
|
||||
# Try to find landing page (slug='landing' or 'home') with three-tier resolution
|
||||
landing_page = content_page_service.get_page_for_vendor(
|
||||
db, slug="landing", vendor_id=vendor.id, include_unpublished=False
|
||||
db, platform_id=platform_id, slug="landing", vendor_id=vendor.id, include_unpublished=False
|
||||
)
|
||||
|
||||
if not landing_page:
|
||||
# Try 'home' slug as fallback
|
||||
landing_page = content_page_service.get_page_for_vendor(
|
||||
db, slug="home", vendor_id=vendor.id, include_unpublished=False
|
||||
db, platform_id=platform_id, slug="home", vendor_id=vendor.id, include_unpublished=False
|
||||
)
|
||||
|
||||
if landing_page:
|
||||
|
||||
Reference in New Issue
Block a user