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:
2025-11-28 19:30:17 +01:00
parent 13f0094743
commit 21c13ca39b
236 changed files with 8450 additions and 6545 deletions

142
main.py
View File

@@ -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)