118 lines
3.6 KiB
Python
118 lines
3.6 KiB
Python
# middleware/theme_context.py
|
|
"""
|
|
Theme Context Middleware
|
|
Injects vendor-specific theme into request context
|
|
"""
|
|
import logging
|
|
from fastapi import Request
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.database import get_db
|
|
from models.database.vendor_theme import VendorTheme
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ThemeContextManager:
|
|
"""Manages theme context for vendor shops."""
|
|
|
|
@staticmethod
|
|
def get_vendor_theme(db: Session, vendor_id: int) -> dict:
|
|
"""
|
|
Get theme configuration for vendor.
|
|
Returns default theme if no custom theme is configured.
|
|
"""
|
|
theme = db.query(VendorTheme).filter(
|
|
VendorTheme.vendor_id == vendor_id,
|
|
VendorTheme.is_active == True
|
|
).first()
|
|
|
|
if theme:
|
|
return theme.to_dict()
|
|
|
|
# Return default theme
|
|
return get_default_theme()
|
|
|
|
@staticmethod
|
|
def get_default_theme() -> dict:
|
|
"""Default theme configuration"""
|
|
return {
|
|
"theme_name": "default",
|
|
"colors": {
|
|
"primary": "#6366f1",
|
|
"secondary": "#8b5cf6",
|
|
"accent": "#ec4899",
|
|
"background": "#ffffff",
|
|
"text": "#1f2937",
|
|
"border": "#e5e7eb"
|
|
},
|
|
"fonts": {
|
|
"heading": "Inter, sans-serif",
|
|
"body": "Inter, sans-serif"
|
|
},
|
|
"branding": {
|
|
"logo": None,
|
|
"logo_dark": None,
|
|
"favicon": None,
|
|
"banner": None
|
|
},
|
|
"layout": {
|
|
"style": "grid",
|
|
"header": "fixed",
|
|
"product_card": "modern"
|
|
},
|
|
"social_links": {},
|
|
"custom_css": None,
|
|
"css_variables": {
|
|
"--color-primary": "#6366f1",
|
|
"--color-secondary": "#8b5cf6",
|
|
"--color-accent": "#ec4899",
|
|
"--color-background": "#ffffff",
|
|
"--color-text": "#1f2937",
|
|
"--color-border": "#e5e7eb",
|
|
"--font-heading": "Inter, sans-serif",
|
|
"--font-body": "Inter, sans-serif",
|
|
}
|
|
}
|
|
|
|
|
|
async def theme_context_middleware(request: Request, call_next):
|
|
"""
|
|
Middleware to inject theme context into request state.
|
|
|
|
This runs AFTER vendor_context_middleware has set request.state.vendor
|
|
"""
|
|
# Only inject theme for shop pages (not admin or API)
|
|
if hasattr(request.state, 'vendor') and request.state.vendor:
|
|
vendor = request.state.vendor
|
|
|
|
# Get database session
|
|
db_gen = get_db()
|
|
db = next(db_gen)
|
|
|
|
try:
|
|
# Get vendor theme
|
|
theme = ThemeContextManager.get_vendor_theme(db, vendor.id)
|
|
request.state.theme = theme
|
|
|
|
logger.debug(
|
|
f"Theme loaded for vendor {vendor.name}: {theme['theme_name']}"
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to load theme for vendor {vendor.id}: {e}")
|
|
# Fallback to default theme
|
|
request.state.theme = ThemeContextManager.get_default_theme()
|
|
finally:
|
|
db.close()
|
|
else:
|
|
# No vendor context, use default theme
|
|
request.state.theme = ThemeContextManager.get_default_theme()
|
|
|
|
response = await call_next(request)
|
|
return response
|
|
|
|
|
|
def get_current_theme(request: Request) -> dict:
|
|
"""Helper function to get current theme from request state."""
|
|
return getattr(request.state, "theme", ThemeContextManager.get_default_theme())
|