Clean up accumulated backward-compat shims, deprecated wrappers, unused aliases, and legacy code across the codebase. Since the platform is not live yet, this establishes a clean baseline. Changes: - Delete deprecated middleware/context.py (RequestContext, get_request_context) - Remove unused factory get_store_email_settings_service() - Remove deprecated pagination_full macro, /admin/platform-homepage route - Remove ConversationResponse, InvoiceSettings* unprefixed aliases - Simplify celery_config.py (remove empty LEGACY_TASK_MODULES) - Standardize billing exceptions: *Error aliases → *Exception names - Consolidate duplicate TierNotFoundError/FeatureNotFoundError classes - Remove deprecated is_admin_request() from Store/PlatformContextManager - Remove is_platform_default field, MediaUploadResponse legacy flat fields - Remove MediaItemResponse.url alias, update JS to use file_url - Update all affected tests and documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
565 lines
20 KiB
Python
565 lines
20 KiB
Python
# tests/integration/middleware/middleware_test_routes.py
|
|
"""
|
|
Test routes for middleware integration tests.
|
|
|
|
These routes are registered at module load time and used by middleware tests
|
|
to verify that store context, theme, and other middleware features work correctly.
|
|
|
|
IMPORTANT: Routes are organized by prefix to avoid conflicts:
|
|
- /middleware-test/* - General middleware testing
|
|
- /api/middleware-test/* - API context testing
|
|
- /admin/middleware-test/* - Admin context testing
|
|
- /store/middleware-test/* - Store dashboard context testing
|
|
- /storefront/middleware-test/* - Storefront context testing
|
|
"""
|
|
|
|
from fastapi import APIRouter, Request
|
|
|
|
# Main test router for general middleware tests
|
|
router = APIRouter(prefix="/middleware-test")
|
|
|
|
|
|
# =============================================================================
|
|
# Store Context Detection Routes
|
|
# =============================================================================
|
|
|
|
|
|
@router.get("/subdomain-detection")
|
|
async def test_subdomain_detection(request: Request):
|
|
"""Test store detection via subdomain routing."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"store_id": store.id if store else None,
|
|
"store_code": store.store_code if store else None,
|
|
"store_name": store.name if store else None,
|
|
"detection_method": "subdomain",
|
|
}
|
|
|
|
|
|
@router.get("/subdomain-port")
|
|
async def test_subdomain_port(request: Request):
|
|
"""Test store detection via subdomain with port number."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"store_code": store.store_code if store else None,
|
|
}
|
|
|
|
|
|
@router.get("/nonexistent-subdomain")
|
|
async def test_nonexistent_subdomain(request: Request):
|
|
"""Test nonexistent subdomain handling."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"store": None, # Don't serialize store object
|
|
}
|
|
|
|
|
|
@router.get("/custom-domain")
|
|
async def test_custom_domain(request: Request):
|
|
"""Test store detection via custom domain."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"store_id": store.id if store else None,
|
|
"store_code": store.store_code if store else None,
|
|
"detection_method": "custom_domain",
|
|
}
|
|
|
|
|
|
@router.get("/custom-domain-www")
|
|
async def test_custom_domain_www(request: Request):
|
|
"""Test store detection via custom domain with www prefix."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"store_code": store.store_code if store else None,
|
|
}
|
|
|
|
|
|
@router.get("/merchant-domain-detection")
|
|
async def test_merchant_domain_detection(request: Request):
|
|
"""Test store detection via merchant domain routing."""
|
|
store = getattr(request.state, "store", None)
|
|
store_context = getattr(request.state, "store_context", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"store_id": store.id if store else None,
|
|
"store_code": store.store_code if store else None,
|
|
"store_name": store.name if store else None,
|
|
"merchant_domain": store_context.get("merchant_domain") if store_context else None,
|
|
"merchant_id": store_context.get("merchant_id") if store_context else None,
|
|
}
|
|
|
|
|
|
@router.get("/inactive-store-detection")
|
|
async def test_inactive_store_detection(request: Request):
|
|
"""Test inactive store detection."""
|
|
store = getattr(request.state, "store", None)
|
|
return {"store_detected": store is not None}
|
|
|
|
|
|
@router.get("/platform-domain")
|
|
async def test_platform_domain(request: Request):
|
|
"""Test platform domain without subdomain."""
|
|
store = getattr(request.state, "store", None)
|
|
return {"store_detected": store is not None}
|
|
|
|
|
|
@router.get("/store-id-injection")
|
|
async def test_store_id_injection(request: Request):
|
|
"""Test store_id injection into request.state."""
|
|
store = getattr(request.state, "store", None)
|
|
store_id = store.id if store else None
|
|
return {
|
|
"has_store_id": store_id is not None,
|
|
"store_id": store_id,
|
|
"store_id_type": type(store_id).__name__ if store_id is not None else None,
|
|
}
|
|
|
|
|
|
@router.get("/store-object-injection")
|
|
async def test_store_object_injection(request: Request):
|
|
"""Test full store object injection into request.state."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"has_store": store is not None,
|
|
"store_attributes": (
|
|
{
|
|
"id": store.id,
|
|
"name": store.name,
|
|
"code": store.store_code,
|
|
"subdomain": store.subdomain,
|
|
"is_active": store.is_active,
|
|
}
|
|
if store
|
|
else None
|
|
),
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# Theme Loading Routes
|
|
# Note: Theme structure is: {"colors": {"primary": ..., "secondary": ...}, "branding": {"logo": ...}, ...}
|
|
# =============================================================================
|
|
|
|
|
|
@router.get("/theme-loading")
|
|
async def test_theme_loading(request: Request):
|
|
"""Test theme loading - full theme data."""
|
|
theme = getattr(request.state, "theme", None)
|
|
# Flatten theme for easier testing
|
|
if theme:
|
|
colors = theme.get("colors", {})
|
|
branding = theme.get("branding", {})
|
|
return {
|
|
"has_theme": True,
|
|
"theme_data": theme,
|
|
"primary_color": colors.get("primary"),
|
|
"secondary_color": colors.get("secondary"),
|
|
"logo_url": branding.get("logo"),
|
|
"favicon_url": branding.get("favicon"),
|
|
"custom_css": theme.get("custom_css"),
|
|
}
|
|
return {"has_theme": False, "theme_data": None}
|
|
|
|
|
|
@router.get("/theme-default")
|
|
async def test_theme_default(request: Request):
|
|
"""Test default theme for store without custom theme."""
|
|
theme = getattr(request.state, "theme", None)
|
|
if theme:
|
|
colors = theme.get("colors", {})
|
|
return {
|
|
"has_theme": True,
|
|
"theme_data": theme,
|
|
"primary_color": colors.get("primary"),
|
|
"secondary_color": colors.get("secondary"),
|
|
}
|
|
return {"has_theme": False, "theme_data": None}
|
|
|
|
|
|
@router.get("/theme-no-store")
|
|
async def test_theme_no_store(request: Request):
|
|
"""Test theme when no store is detected."""
|
|
store = getattr(request.state, "store", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"has_theme": theme is not None,
|
|
"has_store": store is not None,
|
|
}
|
|
|
|
|
|
@router.get("/theme-fields")
|
|
async def test_theme_fields(request: Request):
|
|
"""Test theme contains all expected fields."""
|
|
theme = getattr(request.state, "theme", {}) or {}
|
|
colors = theme.get("colors", {})
|
|
branding = theme.get("branding", {})
|
|
return {
|
|
"primary_color": colors.get("primary"),
|
|
"secondary_color": colors.get("secondary"),
|
|
"logo_url": branding.get("logo"),
|
|
"favicon_url": branding.get("favicon"),
|
|
"custom_css": theme.get("custom_css"),
|
|
}
|
|
|
|
|
|
@router.get("/theme-structure")
|
|
async def test_theme_structure(request: Request):
|
|
"""Test theme structure."""
|
|
theme = getattr(request.state, "theme", {}) or {}
|
|
colors = theme.get("colors", {})
|
|
branding = theme.get("branding", {})
|
|
return {
|
|
"has_primary_color": "primary" in colors,
|
|
"has_secondary_color": "secondary" in colors,
|
|
"has_logo_url": "logo" in branding,
|
|
"has_favicon_url": "favicon" in branding,
|
|
"has_custom_css": "custom_css" in theme,
|
|
}
|
|
|
|
|
|
@router.get("/theme-partial")
|
|
async def test_theme_partial(request: Request):
|
|
"""Test partial theme handling."""
|
|
theme = getattr(request.state, "theme", {}) or {}
|
|
colors = theme.get("colors", {})
|
|
branding = theme.get("branding", {})
|
|
return {
|
|
"has_theme": bool(theme),
|
|
"primary_color": colors.get("primary", "default"),
|
|
"logo_url": branding.get("logo", "default"),
|
|
}
|
|
|
|
|
|
@router.get("/theme-consistency")
|
|
async def test_theme_consistency(request: Request):
|
|
"""Test theme consistency across requests."""
|
|
theme = getattr(request.state, "theme", {}) or {}
|
|
colors = theme.get("colors", {})
|
|
return {"theme_primary": colors.get("primary")}
|
|
|
|
|
|
@router.get("/theme-mutable")
|
|
async def test_theme_mutable(request: Request):
|
|
"""Test theme dict can be read."""
|
|
theme = getattr(request.state, "theme", {}) or {}
|
|
colors = theme.get("colors", {})
|
|
primary = colors.get("primary")
|
|
return {"can_read": primary is not None, "value": primary}
|
|
|
|
|
|
@router.get("/theme-store-dependency")
|
|
async def test_theme_store_dependency(request: Request):
|
|
"""Test theme depends on store middleware."""
|
|
store = getattr(request.state, "store", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"has_store": store is not None,
|
|
"store_id": store.id if store else None,
|
|
"has_theme": theme is not None,
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# Context Detection Routes
|
|
# =============================================================================
|
|
|
|
|
|
@router.get("/context-detection")
|
|
async def test_context_detection(request: Request):
|
|
"""Test context detection."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"context": context_type.value if context_type else None,
|
|
"context_enum": context_type.name if context_type else None,
|
|
"store_detected": store is not None,
|
|
"clean_path": getattr(request.state, "clean_path", None),
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# Middleware Order Routes
|
|
# =============================================================================
|
|
|
|
|
|
@router.get("/middleware-order")
|
|
async def test_middleware_order(request: Request):
|
|
"""Test middleware execution order."""
|
|
store = getattr(request.state, "store", None)
|
|
context_type = getattr(request.state, "context_type", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"store_detected": store is not None,
|
|
"context": context_type.value if context_type else None,
|
|
"theme_loaded": theme is not None,
|
|
"clean_path": getattr(request.state, "clean_path", None),
|
|
"has_clean_path": hasattr(request.state, "clean_path"),
|
|
"has_context_type": context_type is not None,
|
|
}
|
|
|
|
|
|
@router.get("/execution-order")
|
|
async def test_execution_order(request: Request):
|
|
"""Test middleware execution order - detailed."""
|
|
store = getattr(request.state, "store", None)
|
|
context_type = getattr(request.state, "context_type", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
colors = theme.get("colors", {}) if theme else {}
|
|
return {
|
|
"has_store": store is not None,
|
|
"has_clean_path": hasattr(request.state, "clean_path"),
|
|
"has_context_type": context_type is not None,
|
|
"has_theme": theme is not None,
|
|
"theme_primary_color": colors.get("primary"),
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# API Context Test Router
|
|
# =============================================================================
|
|
|
|
api_router = APIRouter(prefix="/api/middleware-test")
|
|
|
|
|
|
@api_router.get("/context")
|
|
async def test_api_context(request: Request):
|
|
"""Test API context detection."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"context_enum": context_type.name if context_type else None,
|
|
}
|
|
|
|
|
|
@api_router.get("/nested-context")
|
|
async def test_nested_api_context(request: Request):
|
|
"""Test nested API path context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {"context_type": context_type.value if context_type else None}
|
|
|
|
|
|
@api_router.get("/store-priority")
|
|
async def test_api_store_priority(request: Request):
|
|
"""Test API context priority over store."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"has_store": store is not None,
|
|
}
|
|
|
|
|
|
@api_router.get("/fallback-context")
|
|
async def test_fallback_context(request: Request):
|
|
"""Test fallback context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"context_enum": context_type.name if context_type else None,
|
|
"has_store": store is not None,
|
|
}
|
|
|
|
|
|
@api_router.get("/clean-path-context")
|
|
async def test_clean_path_context(request: Request):
|
|
"""Test clean path context detection."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"clean_path": getattr(request.state, "clean_path", None),
|
|
"original_path": request.url.path,
|
|
}
|
|
|
|
|
|
@api_router.get("/theme")
|
|
async def test_api_theme(request: Request):
|
|
"""Test theme in API context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"has_store": store is not None,
|
|
"has_theme": theme is not None,
|
|
}
|
|
|
|
|
|
@api_router.get("/missing-store")
|
|
async def test_missing_store(request: Request):
|
|
"""Test missing store handling."""
|
|
store = getattr(request.state, "store", None)
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {
|
|
"has_store": store is not None,
|
|
"store": None, # Don't serialize
|
|
"context_type": context_type.value if context_type else None,
|
|
}
|
|
|
|
|
|
@api_router.get("/inactive-store")
|
|
async def test_inactive_store(request: Request):
|
|
"""Test inactive store handling."""
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"has_store": store is not None,
|
|
"store": None, # Don't serialize
|
|
}
|
|
|
|
|
|
@api_router.get("/admin-subdomain-context")
|
|
async def test_admin_subdomain_context(request: Request):
|
|
"""Test admin subdomain context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {"context_type": context_type.value if context_type else None}
|
|
|
|
|
|
# =============================================================================
|
|
# Admin Context Test Router
|
|
# =============================================================================
|
|
|
|
admin_router = APIRouter(prefix="/admin/middleware-test")
|
|
|
|
|
|
@admin_router.get("/context")
|
|
async def test_admin_context(request: Request):
|
|
"""Test admin context detection."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"context_enum": context_type.name if context_type else None,
|
|
"has_store": store is not None,
|
|
"has_theme": theme is not None,
|
|
}
|
|
|
|
|
|
@admin_router.get("/nested-context")
|
|
async def test_admin_nested_context(request: Request):
|
|
"""Test nested admin path context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {"context_type": context_type.value if context_type else None}
|
|
|
|
|
|
@admin_router.get("/store-priority")
|
|
async def test_admin_store_priority(request: Request):
|
|
"""Test admin context priority over store."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"has_store": store is not None,
|
|
}
|
|
|
|
|
|
@admin_router.get("/no-theme")
|
|
async def test_admin_no_theme(request: Request):
|
|
"""Test admin context has no theme."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"has_theme": theme is not None,
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# Store Dashboard Context Test Router
|
|
# =============================================================================
|
|
|
|
store_router = APIRouter(prefix="/store/middleware-test")
|
|
|
|
|
|
@store_router.get("/context")
|
|
async def test_store_dashboard_context(request: Request):
|
|
"""Test store dashboard context detection."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"context_enum": context_type.name if context_type else None,
|
|
"has_store": store is not None,
|
|
"store_id": store.id if store else None,
|
|
"store_code": store.store_code if store else None,
|
|
}
|
|
|
|
|
|
@store_router.get("/nested-context")
|
|
async def test_store_nested_context(request: Request):
|
|
"""Test nested store dashboard path context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {"context_type": context_type.value if context_type else None}
|
|
|
|
|
|
@store_router.get("/priority")
|
|
async def test_store_priority(request: Request):
|
|
"""Test store dashboard context priority."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
return {"context_type": context_type.value if context_type else None}
|
|
|
|
|
|
@store_router.get("/theme")
|
|
async def test_store_dashboard_theme(request: Request):
|
|
"""Test theme in store dashboard context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
colors = theme.get("colors", {}) if theme else {}
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"has_theme": theme is not None,
|
|
"theme_secondary": colors.get("secondary"),
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# Storefront Context Test Router
|
|
# =============================================================================
|
|
|
|
storefront_router = APIRouter(prefix="/storefront/middleware-test")
|
|
|
|
|
|
@storefront_router.get("/context")
|
|
async def test_storefront_context(request: Request):
|
|
"""Test storefront context detection."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"context_enum": context_type.name if context_type else None,
|
|
"has_store": store is not None,
|
|
"store_id": store.id if store else None,
|
|
"has_theme": theme is not None,
|
|
}
|
|
|
|
|
|
@storefront_router.get("/custom-domain-context")
|
|
async def test_storefront_custom_domain_context(request: Request):
|
|
"""Test storefront context with custom domain."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
store = getattr(request.state, "store", None)
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"store_code": store.store_code if store else None,
|
|
"store_id": store.id if store else None,
|
|
}
|
|
|
|
|
|
@storefront_router.get("/theme")
|
|
async def test_storefront_theme(request: Request):
|
|
"""Test theme in storefront context."""
|
|
context_type = getattr(request.state, "context_type", None)
|
|
theme = getattr(request.state, "theme", None)
|
|
colors = theme.get("colors", {}) if theme else {}
|
|
return {
|
|
"context_type": context_type.value if context_type else None,
|
|
"has_theme": theme is not None,
|
|
"theme_primary": colors.get("primary"),
|
|
}
|