style: apply black and isort formatting across entire codebase
- Standardize quote style (single to double quotes) - Reorder and group imports alphabetically - Fix line breaks and indentation for consistency - Apply PEP 8 formatting standards Also updated Makefile to exclude both venv and .venv from code quality checks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
142
main.py
142
main.py
@@ -9,13 +9,13 @@ Multi-tenant e-commerce marketplace platform with:
|
||||
- Middleware stack for context injection
|
||||
"""
|
||||
|
||||
import sys
|
||||
import io
|
||||
import sys
|
||||
|
||||
# Fix Windows console encoding issues (must be at the very top)
|
||||
if sys.platform == 'win32':
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
if sys.platform == "win32":
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
@@ -23,27 +23,25 @@ from pathlib import Path
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException, Request, Response
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse, FileResponse
|
||||
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.main import api_router
|
||||
|
||||
# Import page routers
|
||||
from app.routes import admin_pages, vendor_pages, shop_pages
|
||||
from app.core.config import settings
|
||||
from app.core.database import get_db
|
||||
from app.core.lifespan import lifespan
|
||||
from app.exceptions.handler import setup_exception_handlers
|
||||
from app.exceptions import ServiceUnavailableException
|
||||
|
||||
from app.exceptions.handler import setup_exception_handlers
|
||||
# Import page routers
|
||||
from app.routes import admin_pages, shop_pages, vendor_pages
|
||||
from middleware.context import ContextMiddleware
|
||||
from middleware.logging import LoggingMiddleware
|
||||
from middleware.theme_context import ThemeContextMiddleware
|
||||
# Import REFACTORED class-based middleware
|
||||
from middleware.vendor_context import VendorContextMiddleware
|
||||
from middleware.context import ContextMiddleware
|
||||
from middleware.theme_context import ThemeContextMiddleware
|
||||
from middleware.logging import LoggingMiddleware
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -146,6 +144,7 @@ app.include_router(api_router, prefix="/api")
|
||||
# FAVICON ROUTES (Must be registered BEFORE page routers)
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def serve_favicon() -> Response:
|
||||
"""
|
||||
Serve favicon with caching headers.
|
||||
@@ -164,7 +163,7 @@ def serve_favicon() -> Response:
|
||||
media_type="image/x-icon",
|
||||
headers={
|
||||
"Cache-Control": "public, max-age=86400", # Cache for 1 day
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return Response(status_code=204)
|
||||
@@ -194,10 +193,7 @@ logger.info("=" * 80)
|
||||
# Admin pages
|
||||
logger.info("Registering admin page routes: /admin/*")
|
||||
app.include_router(
|
||||
admin_pages.router,
|
||||
prefix="/admin",
|
||||
tags=["admin-pages"],
|
||||
include_in_schema=False
|
||||
admin_pages.router, prefix="/admin", tags=["admin-pages"], include_in_schema=False
|
||||
)
|
||||
|
||||
# Vendor management pages (dashboard, products, orders, etc.)
|
||||
@@ -206,7 +202,7 @@ app.include_router(
|
||||
vendor_pages.router,
|
||||
prefix="/vendor",
|
||||
tags=["vendor-pages"],
|
||||
include_in_schema=False
|
||||
include_in_schema=False,
|
||||
)
|
||||
|
||||
# Customer shop pages - Register at TWO prefixes:
|
||||
@@ -217,46 +213,42 @@ logger.info(" - /shop/* (subdomain/custom domain mode)")
|
||||
logger.info(" - /vendors/{code}/shop/* (path-based development mode)")
|
||||
|
||||
app.include_router(
|
||||
shop_pages.router,
|
||||
prefix="/shop",
|
||||
tags=["shop-pages"],
|
||||
include_in_schema=False
|
||||
shop_pages.router, prefix="/shop", tags=["shop-pages"], include_in_schema=False
|
||||
)
|
||||
|
||||
app.include_router(
|
||||
shop_pages.router,
|
||||
prefix="/vendors/{vendor_code}/shop",
|
||||
tags=["shop-pages"],
|
||||
include_in_schema=False
|
||||
include_in_schema=False,
|
||||
)
|
||||
|
||||
|
||||
# Add handler for /vendors/{vendor_code}/ root path
|
||||
@app.get("/vendors/{vendor_code}/", response_class=HTMLResponse, include_in_schema=False)
|
||||
async def vendor_root_path(vendor_code: str, request: Request, db: Session = Depends(get_db)):
|
||||
@app.get(
|
||||
"/vendors/{vendor_code}/", response_class=HTMLResponse, include_in_schema=False
|
||||
)
|
||||
async def vendor_root_path(
|
||||
vendor_code: str, request: Request, db: Session = Depends(get_db)
|
||||
):
|
||||
"""Handle vendor root path (e.g., /vendors/wizamart/)"""
|
||||
# Vendor should already be in request.state from middleware
|
||||
vendor = getattr(request.state, 'vendor', None)
|
||||
vendor = getattr(request.state, "vendor", None)
|
||||
|
||||
if not vendor:
|
||||
raise HTTPException(status_code=404, detail=f"Vendor '{vendor_code}' not found")
|
||||
|
||||
from app.services.content_page_service import content_page_service
|
||||
from app.routes.shop_pages import get_shop_context
|
||||
from app.services.content_page_service import content_page_service
|
||||
|
||||
# Try to find landing page
|
||||
landing_page = content_page_service.get_page_for_vendor(
|
||||
db,
|
||||
slug="landing",
|
||||
vendor_id=vendor.id,
|
||||
include_unpublished=False
|
||||
db, 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, slug="home", vendor_id=vendor.id, include_unpublished=False
|
||||
)
|
||||
|
||||
if landing_page:
|
||||
@@ -265,8 +257,7 @@ async def vendor_root_path(vendor_code: str, request: Request, db: Session = Dep
|
||||
template_path = f"vendor/landing-{template_name}.html"
|
||||
|
||||
return templates.TemplateResponse(
|
||||
template_path,
|
||||
get_shop_context(request, db=db, page=landing_page)
|
||||
template_path, get_shop_context(request, db=db, page=landing_page)
|
||||
)
|
||||
else:
|
||||
# No landing page - redirect to shop
|
||||
@@ -298,22 +289,16 @@ async def platform_homepage(request: Request, db: Session = Depends(get_db)):
|
||||
db,
|
||||
slug="platform_homepage",
|
||||
vendor_id=None, # Platform-level page
|
||||
include_unpublished=False
|
||||
include_unpublished=False,
|
||||
)
|
||||
|
||||
# Load header and footer navigation
|
||||
header_pages = content_page_service.list_pages_for_vendor(
|
||||
db,
|
||||
vendor_id=None,
|
||||
header_only=True,
|
||||
include_unpublished=False
|
||||
db, vendor_id=None, 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
|
||||
db, vendor_id=None, footer_only=True, include_unpublished=False
|
||||
)
|
||||
|
||||
if homepage:
|
||||
@@ -330,7 +315,7 @@ async def platform_homepage(request: Request, db: Session = Depends(get_db)):
|
||||
"page": homepage,
|
||||
"header_pages": header_pages,
|
||||
"footer_pages": footer_pages,
|
||||
}
|
||||
},
|
||||
)
|
||||
else:
|
||||
# Fallback to default static template
|
||||
@@ -342,15 +327,13 @@ async def platform_homepage(request: Request, db: Session = Depends(get_db)):
|
||||
"request": request,
|
||||
"header_pages": header_pages,
|
||||
"footer_pages": footer_pages,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@app.get("/{slug}", response_class=HTMLResponse, include_in_schema=False)
|
||||
async def platform_content_page(
|
||||
request: Request,
|
||||
slug: str,
|
||||
db: Session = Depends(get_db)
|
||||
request: Request, slug: str, db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Platform content pages: /about, /faq, /terms, /contact, etc.
|
||||
@@ -366,10 +349,7 @@ async def platform_content_page(
|
||||
|
||||
# Load page from CMS
|
||||
page = content_page_service.get_page_for_vendor(
|
||||
db,
|
||||
slug=slug,
|
||||
vendor_id=None, # Platform pages only
|
||||
include_unpublished=False
|
||||
db, slug=slug, vendor_id=None, include_unpublished=False # Platform pages only
|
||||
)
|
||||
|
||||
if not page:
|
||||
@@ -378,17 +358,11 @@ async def platform_content_page(
|
||||
|
||||
# Load header and footer navigation
|
||||
header_pages = content_page_service.list_pages_for_vendor(
|
||||
db,
|
||||
vendor_id=None,
|
||||
header_only=True,
|
||||
include_unpublished=False
|
||||
db, vendor_id=None, 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
|
||||
db, vendor_id=None, footer_only=True, include_unpublished=False
|
||||
)
|
||||
|
||||
logger.info(f"[PLATFORM] Rendering content page: {page.title} (/{slug})")
|
||||
@@ -400,7 +374,7 @@ async def platform_content_page(
|
||||
"page": page,
|
||||
"header_pages": header_pages,
|
||||
"footer_pages": footer_pages,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -411,8 +385,8 @@ logger.info("=" * 80)
|
||||
logger.info("REGISTERED ROUTES SUMMARY")
|
||||
logger.info("=" * 80)
|
||||
for route in app.routes:
|
||||
if hasattr(route, 'methods') and hasattr(route, 'path'):
|
||||
methods = ', '.join(route.methods) if route.methods else 'N/A'
|
||||
if hasattr(route, "methods") and hasattr(route, "path"):
|
||||
methods = ", ".join(route.methods) if route.methods else "N/A"
|
||||
logger.info(f" {methods:<10} {route.path:<60}")
|
||||
logger.info("=" * 80)
|
||||
|
||||
@@ -420,6 +394,7 @@ logger.info("=" * 80)
|
||||
# API ROUTES (JSON Responses)
|
||||
# ============================================================================
|
||||
|
||||
|
||||
# Public Routes (no authentication required)
|
||||
@app.get("/", response_class=HTMLResponse, include_in_schema=False)
|
||||
async def root(request: Request, db: Session = Depends(get_db)):
|
||||
@@ -428,7 +403,7 @@ async def root(request: Request, db: Session = Depends(get_db)):
|
||||
- If vendor detected (domain/subdomain): Show vendor landing page or redirect to shop
|
||||
- If no vendor (platform root): Redirect to documentation
|
||||
"""
|
||||
vendor = getattr(request.state, 'vendor', None)
|
||||
vendor = getattr(request.state, "vendor", None)
|
||||
|
||||
if vendor:
|
||||
# Vendor context detected - serve landing page
|
||||
@@ -436,19 +411,13 @@ async def root(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
# Try to find landing page (slug='landing' or 'home')
|
||||
landing_page = content_page_service.get_page_for_vendor(
|
||||
db,
|
||||
slug="landing",
|
||||
vendor_id=vendor.id,
|
||||
include_unpublished=False
|
||||
db, 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, slug="home", vendor_id=vendor.id, include_unpublished=False
|
||||
)
|
||||
|
||||
if landing_page:
|
||||
@@ -459,17 +428,26 @@ async def root(request: Request, db: Session = Depends(get_db)):
|
||||
template_path = f"vendor/landing-{template_name}.html"
|
||||
|
||||
return templates.TemplateResponse(
|
||||
template_path,
|
||||
get_shop_context(request, db=db, page=landing_page)
|
||||
template_path, get_shop_context(request, db=db, page=landing_page)
|
||||
)
|
||||
else:
|
||||
# No landing page - redirect to shop
|
||||
vendor_context = getattr(request.state, 'vendor_context', None)
|
||||
access_method = vendor_context.get('detection_method', 'unknown') if vendor_context else 'unknown'
|
||||
vendor_context = getattr(request.state, "vendor_context", None)
|
||||
access_method = (
|
||||
vendor_context.get("detection_method", "unknown")
|
||||
if vendor_context
|
||||
else "unknown"
|
||||
)
|
||||
|
||||
if access_method == "path":
|
||||
full_prefix = vendor_context.get('full_prefix', '/vendor/') if vendor_context else '/vendor/'
|
||||
return RedirectResponse(url=f"{full_prefix}{vendor.subdomain}/shop/", status_code=302)
|
||||
full_prefix = (
|
||||
vendor_context.get("full_prefix", "/vendor/")
|
||||
if vendor_context
|
||||
else "/vendor/"
|
||||
)
|
||||
return RedirectResponse(
|
||||
url=f"{full_prefix}{vendor.subdomain}/shop/", status_code=302
|
||||
)
|
||||
else:
|
||||
# Domain/subdomain
|
||||
return RedirectResponse(url="/shop/", status_code=302)
|
||||
|
||||
Reference in New Issue
Block a user