refactor: migrate messaging and media routes to modules

Messaging module (communication):
- vendor_messages.py: Conversation and message management
- vendor_notifications.py: Vendor notifications
- vendor_email_settings.py: SMTP and provider configuration
- vendor_email_templates.py: Email template customization

CMS module (content management):
- vendor_media.py: Media library management
- vendor_content_pages.py: Content page overrides

All routes auto-discovered via is_self_contained=True.
Deleted 5 legacy files from app/api/v1/vendor/.
app/api/v1/vendor/ now empty except for __init__.py (auto-discovery only).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 15:21:25 +01:00
parent da3f28849e
commit 7639ca602b
12 changed files with 385 additions and 410 deletions

View File

@@ -1,278 +1,25 @@
# app/modules/cms/routes/api/vendor.py
"""
Vendor Content Pages API
CMS module vendor API routes.
Vendor Context: Uses token_vendor_id from JWT token (authenticated vendor API pattern).
The get_current_vendor_api dependency guarantees token_vendor_id is present.
Vendors can:
- View their content pages (includes platform defaults)
- Create/edit/delete their own content page overrides
- Preview pages before publishing
Aggregates all vendor CMS routes:
- /content-pages/* - Content page management
- /media/* - Media library management
"""
import logging
from fastapi import APIRouter
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.api.deps import get_current_vendor_api, get_db
from app.modules.cms.exceptions import ContentPageNotFoundException
from app.modules.cms.schemas import (
VendorContentPageCreate,
VendorContentPageUpdate,
ContentPageResponse,
CMSUsageResponse,
)
from app.modules.cms.services import content_page_service
from app.services.vendor_service import VendorService # noqa: MOD-004 - shared platform service
from models.database.user import User
from .vendor_content_pages import vendor_content_pages_router
from .vendor_media import vendor_media_router
# Route configuration for auto-discovery
ROUTE_CONFIG = {
"prefix": "/content-pages",
"tags": ["vendor-content-pages"],
"priority": 100, # Register last (CMS has catch-all slug routes)
}
vendor_service = VendorService()
vendor_router = APIRouter()
router = vendor_router # Alias for discovery compatibility
router = APIRouter()
vendor_router = router # Alias for discovery compatibility
logger = logging.getLogger(__name__)
# ============================================================================
# VENDOR CONTENT PAGES
# ============================================================================
@router.get("/", response_model=list[ContentPageResponse])
def list_vendor_pages(
include_unpublished: bool = Query(False, description="Include draft pages"),
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
List all content pages available for this vendor.
Returns vendor-specific overrides + platform defaults (vendor overrides take precedence).
"""
pages = content_page_service.list_pages_for_vendor(
db, vendor_id=current_user.token_vendor_id, include_unpublished=include_unpublished
)
return [page.to_dict() for page in pages]
@router.get("/overrides", response_model=list[ContentPageResponse])
def list_vendor_overrides(
include_unpublished: bool = Query(False, description="Include draft pages"),
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
List only vendor-specific content pages (no platform defaults).
Shows what the vendor has customized.
"""
pages = content_page_service.list_all_vendor_pages(
db, vendor_id=current_user.token_vendor_id, include_unpublished=include_unpublished
)
return [page.to_dict() for page in pages]
@router.get("/usage", response_model=CMSUsageResponse)
def get_cms_usage(
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get CMS usage statistics for the vendor.
Returns page counts and limits based on subscription tier.
"""
vendor = vendor_service.get_vendor_by_id_optional(db, current_user.token_vendor_id)
if not vendor:
return CMSUsageResponse(
total_pages=0,
custom_pages=0,
override_pages=0,
pages_limit=3,
custom_pages_limit=0,
can_create_page=False,
can_create_custom=False,
usage_percent=0,
custom_usage_percent=0,
)
# Get vendor's pages
vendor_pages = content_page_service.list_all_vendor_pages(
db, vendor_id=current_user.token_vendor_id, include_unpublished=True
)
total_pages = len(vendor_pages)
override_pages = sum(1 for p in vendor_pages if p.is_vendor_override)
custom_pages = total_pages - override_pages
# Get limits from subscription tier
pages_limit = None
custom_pages_limit = None
if vendor.subscription and vendor.subscription.tier:
pages_limit = vendor.subscription.tier.cms_pages_limit
custom_pages_limit = vendor.subscription.tier.cms_custom_pages_limit
# Calculate can_create flags
can_create_page = pages_limit is None or total_pages < pages_limit
can_create_custom = custom_pages_limit is None or custom_pages < custom_pages_limit
# Calculate usage percentages
usage_percent = 0 if pages_limit is None else min(100, (total_pages / pages_limit) * 100) if pages_limit > 0 else 100
custom_usage_percent = 0 if custom_pages_limit is None else min(100, (custom_pages / custom_pages_limit) * 100) if custom_pages_limit > 0 else 100
return CMSUsageResponse(
total_pages=total_pages,
custom_pages=custom_pages,
override_pages=override_pages,
pages_limit=pages_limit,
custom_pages_limit=custom_pages_limit,
can_create_page=can_create_page,
can_create_custom=can_create_custom,
usage_percent=usage_percent,
custom_usage_percent=custom_usage_percent,
)
@router.get("/platform-default/{slug}", response_model=ContentPageResponse)
def get_platform_default(
slug: str,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get the platform default content for a slug.
Useful for vendors to view the original before/after overriding.
"""
# Get vendor's platform
vendor = vendor_service.get_vendor_by_id_optional(db, current_user.token_vendor_id)
platform_id = 1 # Default to OMS
if vendor and vendor.platforms:
platform_id = vendor.platforms[0].id
# Get platform default (vendor_id=None)
page = content_page_service.get_vendor_default_page(
db, platform_id=platform_id, slug=slug, include_unpublished=True
)
if not page:
raise ContentPageNotFoundException(slug)
return page.to_dict()
@router.get("/{slug}", response_model=ContentPageResponse)
def get_page(
slug: str,
include_unpublished: bool = Query(False, description="Include draft pages"),
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get a specific content page by slug.
Returns vendor override if exists, otherwise platform default.
"""
page = content_page_service.get_page_for_vendor_or_raise(
db,
slug=slug,
vendor_id=current_user.token_vendor_id,
include_unpublished=include_unpublished,
)
return page.to_dict()
@router.post("/", response_model=ContentPageResponse, status_code=201)
def create_vendor_page(
page_data: VendorContentPageCreate,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Create a vendor-specific content page override.
This will be shown instead of the platform default for this vendor.
"""
page = content_page_service.create_page(
db,
slug=page_data.slug,
title=page_data.title,
content=page_data.content,
vendor_id=current_user.token_vendor_id,
content_format=page_data.content_format,
meta_description=page_data.meta_description,
meta_keywords=page_data.meta_keywords,
is_published=page_data.is_published,
show_in_footer=page_data.show_in_footer,
show_in_header=page_data.show_in_header,
show_in_legal=page_data.show_in_legal,
display_order=page_data.display_order,
created_by=current_user.id,
)
db.commit()
return page.to_dict()
@router.put("/{page_id}", response_model=ContentPageResponse)
def update_vendor_page(
page_id: int,
page_data: VendorContentPageUpdate,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Update a vendor-specific content page.
Can only update pages owned by this vendor.
"""
# Update with ownership check in service layer
page = content_page_service.update_vendor_page(
db,
page_id=page_id,
vendor_id=current_user.token_vendor_id,
title=page_data.title,
content=page_data.content,
content_format=page_data.content_format,
meta_description=page_data.meta_description,
meta_keywords=page_data.meta_keywords,
is_published=page_data.is_published,
show_in_footer=page_data.show_in_footer,
show_in_header=page_data.show_in_header,
show_in_legal=page_data.show_in_legal,
display_order=page_data.display_order,
updated_by=current_user.id,
)
db.commit()
return page.to_dict()
@router.delete("/{page_id}", status_code=204)
def delete_vendor_page(
page_id: int,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Delete a vendor-specific content page.
Can only delete pages owned by this vendor.
After deletion, platform default will be shown (if exists).
"""
# Delete with ownership check in service layer
content_page_service.delete_vendor_page(db, page_id, current_user.token_vendor_id)
db.commit()
# Aggregate all CMS vendor routes
vendor_router.include_router(vendor_content_pages_router, tags=["vendor-content-pages"])
vendor_router.include_router(vendor_media_router, tags=["vendor-media"])

View File

@@ -0,0 +1,270 @@
# app/modules/cms/routes/api/vendor_content_pages.py
"""
Vendor Content Pages API
Vendor Context: Uses token_vendor_id from JWT token (authenticated vendor API pattern).
The get_current_vendor_api dependency guarantees token_vendor_id is present.
Vendors can:
- View their content pages (includes platform defaults)
- Create/edit/delete their own content page overrides
- Preview pages before publishing
"""
import logging
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.api.deps import get_current_vendor_api, get_db
from app.modules.cms.exceptions import ContentPageNotFoundException
from app.modules.cms.schemas import (
VendorContentPageCreate,
VendorContentPageUpdate,
ContentPageResponse,
CMSUsageResponse,
)
from app.modules.cms.services import content_page_service
from app.services.vendor_service import VendorService # noqa: MOD-004 - shared platform service
from models.database.user import User
vendor_service = VendorService()
vendor_content_pages_router = APIRouter(prefix="/content-pages")
logger = logging.getLogger(__name__)
# ============================================================================
# VENDOR CONTENT PAGES
# ============================================================================
@vendor_content_pages_router.get("/", response_model=list[ContentPageResponse])
def list_vendor_pages(
include_unpublished: bool = Query(False, description="Include draft pages"),
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
List all content pages available for this vendor.
Returns vendor-specific overrides + platform defaults (vendor overrides take precedence).
"""
pages = content_page_service.list_pages_for_vendor(
db, vendor_id=current_user.token_vendor_id, include_unpublished=include_unpublished
)
return [page.to_dict() for page in pages]
@vendor_content_pages_router.get("/overrides", response_model=list[ContentPageResponse])
def list_vendor_overrides(
include_unpublished: bool = Query(False, description="Include draft pages"),
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
List only vendor-specific content pages (no platform defaults).
Shows what the vendor has customized.
"""
pages = content_page_service.list_all_vendor_pages(
db, vendor_id=current_user.token_vendor_id, include_unpublished=include_unpublished
)
return [page.to_dict() for page in pages]
@vendor_content_pages_router.get("/usage", response_model=CMSUsageResponse)
def get_cms_usage(
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get CMS usage statistics for the vendor.
Returns page counts and limits based on subscription tier.
"""
vendor = vendor_service.get_vendor_by_id_optional(db, current_user.token_vendor_id)
if not vendor:
return CMSUsageResponse(
total_pages=0,
custom_pages=0,
override_pages=0,
pages_limit=3,
custom_pages_limit=0,
can_create_page=False,
can_create_custom=False,
usage_percent=0,
custom_usage_percent=0,
)
# Get vendor's pages
vendor_pages = content_page_service.list_all_vendor_pages(
db, vendor_id=current_user.token_vendor_id, include_unpublished=True
)
total_pages = len(vendor_pages)
override_pages = sum(1 for p in vendor_pages if p.is_vendor_override)
custom_pages = total_pages - override_pages
# Get limits from subscription tier
pages_limit = None
custom_pages_limit = None
if vendor.subscription and vendor.subscription.tier:
pages_limit = vendor.subscription.tier.cms_pages_limit
custom_pages_limit = vendor.subscription.tier.cms_custom_pages_limit
# Calculate can_create flags
can_create_page = pages_limit is None or total_pages < pages_limit
can_create_custom = custom_pages_limit is None or custom_pages < custom_pages_limit
# Calculate usage percentages
usage_percent = 0 if pages_limit is None else min(100, (total_pages / pages_limit) * 100) if pages_limit > 0 else 100
custom_usage_percent = 0 if custom_pages_limit is None else min(100, (custom_pages / custom_pages_limit) * 100) if custom_pages_limit > 0 else 100
return CMSUsageResponse(
total_pages=total_pages,
custom_pages=custom_pages,
override_pages=override_pages,
pages_limit=pages_limit,
custom_pages_limit=custom_pages_limit,
can_create_page=can_create_page,
can_create_custom=can_create_custom,
usage_percent=usage_percent,
custom_usage_percent=custom_usage_percent,
)
@vendor_content_pages_router.get("/platform-default/{slug}", response_model=ContentPageResponse)
def get_platform_default(
slug: str,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get the platform default content for a slug.
Useful for vendors to view the original before/after overriding.
"""
# Get vendor's platform
vendor = vendor_service.get_vendor_by_id_optional(db, current_user.token_vendor_id)
platform_id = 1 # Default to OMS
if vendor and vendor.platforms:
platform_id = vendor.platforms[0].id
# Get platform default (vendor_id=None)
page = content_page_service.get_vendor_default_page(
db, platform_id=platform_id, slug=slug, include_unpublished=True
)
if not page:
raise ContentPageNotFoundException(slug)
return page.to_dict()
@vendor_content_pages_router.get("/{slug}", response_model=ContentPageResponse)
def get_page(
slug: str,
include_unpublished: bool = Query(False, description="Include draft pages"),
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get a specific content page by slug.
Returns vendor override if exists, otherwise platform default.
"""
page = content_page_service.get_page_for_vendor_or_raise(
db,
slug=slug,
vendor_id=current_user.token_vendor_id,
include_unpublished=include_unpublished,
)
return page.to_dict()
@vendor_content_pages_router.post("/", response_model=ContentPageResponse, status_code=201)
def create_vendor_page(
page_data: VendorContentPageCreate,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Create a vendor-specific content page override.
This will be shown instead of the platform default for this vendor.
"""
page = content_page_service.create_page(
db,
slug=page_data.slug,
title=page_data.title,
content=page_data.content,
vendor_id=current_user.token_vendor_id,
content_format=page_data.content_format,
meta_description=page_data.meta_description,
meta_keywords=page_data.meta_keywords,
is_published=page_data.is_published,
show_in_footer=page_data.show_in_footer,
show_in_header=page_data.show_in_header,
show_in_legal=page_data.show_in_legal,
display_order=page_data.display_order,
created_by=current_user.id,
)
db.commit()
return page.to_dict()
@vendor_content_pages_router.put("/{page_id}", response_model=ContentPageResponse)
def update_vendor_page(
page_id: int,
page_data: VendorContentPageUpdate,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Update a vendor-specific content page.
Can only update pages owned by this vendor.
"""
# Update with ownership check in service layer
page = content_page_service.update_vendor_page(
db,
page_id=page_id,
vendor_id=current_user.token_vendor_id,
title=page_data.title,
content=page_data.content,
content_format=page_data.content_format,
meta_description=page_data.meta_description,
meta_keywords=page_data.meta_keywords,
is_published=page_data.is_published,
show_in_footer=page_data.show_in_footer,
show_in_header=page_data.show_in_header,
show_in_legal=page_data.show_in_legal,
display_order=page_data.display_order,
updated_by=current_user.id,
)
db.commit()
return page.to_dict()
@vendor_content_pages_router.delete("/{page_id}", status_code=204)
def delete_vendor_page(
page_id: int,
current_user: User = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Delete a vendor-specific content page.
Can only delete pages owned by this vendor.
After deletion, platform default will be shown (if exists).
"""
# Delete with ownership check in service layer
content_page_service.delete_vendor_page(db, page_id, current_user.token_vendor_id)
db.commit()

View File

@@ -0,0 +1,304 @@
# app/modules/cms/routes/api/vendor_media.py
"""
Vendor media and file management endpoints.
Vendor Context: Uses token_vendor_id from JWT token (authenticated vendor API pattern).
The get_current_vendor_api dependency guarantees token_vendor_id is present.
"""
import logging
from fastapi import APIRouter, Depends, File, Query, UploadFile
from sqlalchemy.orm import Session
from app.api.deps import get_current_vendor_api
from app.core.database import get_db
from app.exceptions.media import MediaOptimizationException
from app.services.media_service import media_service
from models.schema.auth import UserContext
from models.schema.media import (
MediaDetailResponse,
MediaItemResponse,
MediaListResponse,
MediaMetadataUpdate,
MediaUploadResponse,
MediaUsageResponse,
MultipleUploadResponse,
OptimizationResultResponse,
UploadedFileInfo,
FailedFileInfo,
)
vendor_media_router = APIRouter(prefix="/media")
logger = logging.getLogger(__name__)
@vendor_media_router.get("", response_model=MediaListResponse)
def get_media_library(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
media_type: str | None = Query(None, description="image, video, document"),
folder: str | None = Query(None, description="Filter by folder"),
search: str | None = Query(None),
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get vendor media library.
- Get all media files for vendor
- Filter by type (image, video, document)
- Filter by folder
- Search by filename
- Support pagination
"""
media_files, total = media_service.get_media_library(
db=db,
vendor_id=current_user.token_vendor_id,
skip=skip,
limit=limit,
media_type=media_type,
folder=folder,
search=search,
)
return MediaListResponse(
media=[MediaItemResponse.model_validate(m) for m in media_files],
total=total,
skip=skip,
limit=limit,
)
@vendor_media_router.post("/upload", response_model=MediaUploadResponse)
async def upload_media(
file: UploadFile = File(...),
folder: str | None = Query("general", description="products, general, etc."),
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Upload media file.
- Accept file upload
- Validate file type and size
- Store file in vendor-specific directory
- Generate thumbnails for images
- Save metadata to database
- Return file URL
"""
# Read file content
file_content = await file.read()
# Upload using service (exceptions will propagate to handler)
media_file = await media_service.upload_file(
db=db,
vendor_id=current_user.token_vendor_id,
file_content=file_content,
filename=file.filename or "unnamed",
folder=folder or "general",
)
db.commit()
return MediaUploadResponse(
id=media_file.id,
file_url=media_file.file_url,
thumbnail_url=media_file.thumbnail_url,
filename=media_file.original_filename,
file_size=media_file.file_size,
media_type=media_file.media_type,
message="File uploaded successfully",
)
@vendor_media_router.post("/upload/multiple", response_model=MultipleUploadResponse)
async def upload_multiple_media(
files: list[UploadFile] = File(...),
folder: str | None = Query("general"),
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Upload multiple media files at once.
- Accept multiple files
- Process each file
- Return list of uploaded file URLs
- Handle errors gracefully
"""
uploaded = []
failed = []
for file in files:
try:
file_content = await file.read()
media_file = await media_service.upload_file(
db=db,
vendor_id=current_user.token_vendor_id,
file_content=file_content,
filename=file.filename or "unnamed",
folder=folder or "general",
)
uploaded.append(UploadedFileInfo(
id=media_file.id,
filename=media_file.original_filename or media_file.filename,
file_url=media_file.file_url,
thumbnail_url=media_file.thumbnail_url,
))
except Exception as e:
logger.warning(f"Failed to upload {file.filename}: {e}")
failed.append(FailedFileInfo(
filename=file.filename or "unnamed",
error=str(e),
))
db.commit()
return MultipleUploadResponse(
uploaded_files=uploaded,
failed_files=failed,
total_uploaded=len(uploaded),
total_failed=len(failed),
message=f"Uploaded {len(uploaded)} files, {len(failed)} failed",
)
@vendor_media_router.get("/{media_id}", response_model=MediaDetailResponse)
def get_media_details(
media_id: int,
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get media file details.
- Get file metadata
- Return file URL
- Return basic info
"""
# Service will raise MediaNotFoundException if not found
media = media_service.get_media(
db=db,
vendor_id=current_user.token_vendor_id,
media_id=media_id,
)
return MediaDetailResponse.model_validate(media)
@vendor_media_router.put("/{media_id}", response_model=MediaDetailResponse)
def update_media_metadata(
media_id: int,
metadata: MediaMetadataUpdate,
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Update media file metadata.
- Update filename
- Update alt text
- Update description
- Move to different folder
"""
# Service will raise MediaNotFoundException if not found
media = media_service.update_media_metadata(
db=db,
vendor_id=current_user.token_vendor_id,
media_id=media_id,
filename=metadata.filename,
alt_text=metadata.alt_text,
description=metadata.description,
folder=metadata.folder,
metadata=metadata.metadata,
)
db.commit()
return MediaDetailResponse.model_validate(media)
@vendor_media_router.delete("/{media_id}", response_model=MediaDetailResponse)
def delete_media(
media_id: int,
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Delete media file.
- Verify file belongs to vendor
- Delete file from storage
- Delete database record
- Return success/error
"""
# Service will raise MediaNotFoundException if not found
media_service.delete_media(
db=db,
vendor_id=current_user.token_vendor_id,
media_id=media_id,
)
db.commit()
return MediaDetailResponse(message="Media file deleted successfully")
@vendor_media_router.get("/{media_id}/usage", response_model=MediaUsageResponse)
def get_media_usage(
media_id: int,
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Get where this media file is being used.
- Check products using this media
- Return list of usage
"""
# Service will raise MediaNotFoundException if not found
usage = media_service.get_media_usage(
db=db,
vendor_id=current_user.token_vendor_id,
media_id=media_id,
)
return MediaUsageResponse(**usage)
@vendor_media_router.post("/optimize/{media_id}", response_model=OptimizationResultResponse)
def optimize_media(
media_id: int,
current_user: UserContext = Depends(get_current_vendor_api),
db: Session = Depends(get_db),
):
"""
Optimize media file (compress, resize, etc.).
Note: Image optimization requires PIL/Pillow to be installed.
"""
# Service will raise MediaNotFoundException if not found
media = media_service.get_media(
db=db,
vendor_id=current_user.token_vendor_id,
media_id=media_id,
)
if media.media_type != "image":
raise MediaOptimizationException("Only images can be optimized")
# For now, return current state - optimization is done on upload
return OptimizationResultResponse(
media_id=media_id,
original_size=media.file_size,
optimized_size=media.optimized_size or media.file_size,
savings_percent=0.0 if not media.optimized_size else
round((1 - media.optimized_size / media.file_size) * 100, 1),
optimized_url=media.file_url,
message="Image optimization applied on upload" if media.is_optimized
else "Image not yet optimized",
)

View File

@@ -2,38 +2,15 @@
"""
CMS module vendor routes.
This module wraps the existing vendor content pages and media routes
and adds module-based access control. Routes are re-exported from the
original location with the module access dependency.
Re-exports routes from the API routes for backwards compatibility
with the lazy router attachment pattern.
Includes:
- /content-pages/* - Content page management
- /media/* - Media library
"""
from fastapi import APIRouter, Depends
# Re-export vendor_router from API routes
from app.modules.cms.routes.api.vendor import vendor_router
from app.api.deps import require_module_access
# Import original routers (direct import to avoid circular dependency)
from app.api.v1.vendor.content_pages import router as content_original_router
from app.api.v1.vendor.media import router as media_original_router
# Create module-aware router for content pages
vendor_router = APIRouter(
prefix="/content-pages",
dependencies=[Depends(require_module_access("cms"))],
)
# Re-export all routes from the original content pages module
for route in content_original_router.routes:
vendor_router.routes.append(route)
# Create separate router for media library
vendor_media_router = APIRouter(
prefix="/media",
dependencies=[Depends(require_module_access("cms"))],
)
for route in media_original_router.routes:
vendor_media_router.routes.append(route)
__all__ = ["vendor_router"]