fix(api): use proper Pydantic models in vendor themes/domains
vendor_themes.py: - Return ThemePresetListResponse instead of raw dict (API-001 fix) - Add ThemePresetResponse response_model to apply_theme_preset - Add ThemeDeleteResponse response_model to delete endpoint vendor_domain.py: - Remove _get_vendor_by_id helper with direct DB query - Use vendor_service.get_vendor_by_id() instead (API-002 fix) models/schema/vendor_theme.py: - Add ThemeDeleteResponse model for delete endpoint response 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ Admin endpoints for managing vendor custom domains.
|
|||||||
Follows the architecture pattern:
|
Follows the architecture pattern:
|
||||||
- Endpoints only handle HTTP layer
|
- Endpoints only handle HTTP layer
|
||||||
- Business logic in service layer
|
- Business logic in service layer
|
||||||
- Proper exception handling
|
- Domain exceptions bubble up to global handler
|
||||||
- Pydantic schemas for validation
|
- Pydantic schemas for validation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -16,10 +16,9 @@ from sqlalchemy.orm import Session
|
|||||||
|
|
||||||
from app.api.deps import get_current_admin_api
|
from app.api.deps import get_current_admin_api
|
||||||
from app.core.database import get_db
|
from app.core.database import get_db
|
||||||
from app.exceptions import VendorNotFoundException
|
|
||||||
from app.services.vendor_domain_service import vendor_domain_service
|
from app.services.vendor_domain_service import vendor_domain_service
|
||||||
|
from app.services.vendor_service import vendor_service
|
||||||
from models.database.user import User
|
from models.database.user import User
|
||||||
from models.database.vendor import Vendor
|
|
||||||
from models.schema.vendor_domain import (
|
from models.schema.vendor_domain import (
|
||||||
DomainDeletionResponse,
|
DomainDeletionResponse,
|
||||||
DomainVerificationInstructions,
|
DomainVerificationInstructions,
|
||||||
@@ -34,26 +33,6 @@ router = APIRouter(prefix="/vendors")
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _get_vendor_by_id(db: Session, vendor_id: int) -> Vendor:
|
|
||||||
"""
|
|
||||||
Helper to get vendor by ID.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
db: Database session
|
|
||||||
vendor_id: Vendor ID
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Vendor object
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
VendorNotFoundException: If vendor not found
|
|
||||||
"""
|
|
||||||
vendor = db.query(Vendor).filter(Vendor.id == vendor_id).first()
|
|
||||||
if not vendor:
|
|
||||||
raise VendorNotFoundException(str(vendor_id), identifier_type="id")
|
|
||||||
return vendor
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{vendor_id}/domains", response_model=VendorDomainResponse)
|
@router.post("/{vendor_id}/domains", response_model=VendorDomainResponse)
|
||||||
def add_vendor_domain(
|
def add_vendor_domain(
|
||||||
vendor_id: int = Path(..., description="Vendor ID", gt=0),
|
vendor_id: int = Path(..., description="Vendor ID", gt=0),
|
||||||
@@ -122,8 +101,8 @@ def list_vendor_domains(
|
|||||||
**Raises:**
|
**Raises:**
|
||||||
- 404: Vendor not found
|
- 404: Vendor not found
|
||||||
"""
|
"""
|
||||||
# Verify vendor exists
|
# Verify vendor exists (raises VendorNotFoundException if not found)
|
||||||
_get_vendor_by_id(db, vendor_id)
|
vendor_service.get_vendor_by_id(db, vendor_id)
|
||||||
|
|
||||||
domains = vendor_domain_service.get_vendor_domains(db, vendor_id)
|
domains = vendor_domain_service.get_vendor_domains(db, vendor_id)
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ from app.api.deps import get_current_admin_api, get_db
|
|||||||
from app.services.vendor_theme_service import vendor_theme_service
|
from app.services.vendor_theme_service import vendor_theme_service
|
||||||
from models.database.user import User
|
from models.database.user import User
|
||||||
from models.schema.vendor_theme import (
|
from models.schema.vendor_theme import (
|
||||||
|
ThemeDeleteResponse,
|
||||||
ThemePresetListResponse,
|
ThemePresetListResponse,
|
||||||
|
ThemePresetResponse,
|
||||||
VendorThemeResponse,
|
VendorThemeResponse,
|
||||||
VendorThemeUpdate,
|
VendorThemeUpdate,
|
||||||
)
|
)
|
||||||
@@ -51,7 +53,7 @@ async def get_theme_presets(current_admin: User = Depends(get_current_admin_api)
|
|||||||
logger.info("Getting theme presets")
|
logger.info("Getting theme presets")
|
||||||
|
|
||||||
presets = vendor_theme_service.get_available_presets()
|
presets = vendor_theme_service.get_available_presets()
|
||||||
return {"presets": presets}
|
return ThemePresetListResponse(presets=presets)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -134,7 +136,7 @@ async def update_vendor_theme(
|
|||||||
# Service handles all validation and raises appropriate exceptions
|
# Service handles all validation and raises appropriate exceptions
|
||||||
# Global exception handler converts them to proper HTTP responses
|
# Global exception handler converts them to proper HTTP responses
|
||||||
theme = vendor_theme_service.update_theme(db, vendor_code, theme_data)
|
theme = vendor_theme_service.update_theme(db, vendor_code, theme_data)
|
||||||
return theme.to_dict()
|
return VendorThemeResponse(**theme.to_dict())
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -142,7 +144,7 @@ async def update_vendor_theme(
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{vendor_code}/preset/{preset_name}")
|
@router.post("/{vendor_code}/preset/{preset_name}", response_model=ThemePresetResponse)
|
||||||
async def apply_theme_preset(
|
async def apply_theme_preset(
|
||||||
vendor_code: str = Path(..., description="Vendor code"),
|
vendor_code: str = Path(..., description="Vendor code"),
|
||||||
preset_name: str = Path(..., description="Preset name"),
|
preset_name: str = Path(..., description="Preset name"),
|
||||||
@@ -184,10 +186,10 @@ async def apply_theme_preset(
|
|||||||
# Global exception handler converts to HTTP 404
|
# Global exception handler converts to HTTP 404
|
||||||
theme = vendor_theme_service.apply_theme_preset(db, vendor_code, preset_name)
|
theme = vendor_theme_service.apply_theme_preset(db, vendor_code, preset_name)
|
||||||
|
|
||||||
return {
|
return ThemePresetResponse(
|
||||||
"message": f"Applied {preset_name} preset successfully",
|
message=f"Applied {preset_name} preset successfully",
|
||||||
"theme": theme.to_dict(),
|
theme=VendorThemeResponse(**theme.to_dict()),
|
||||||
}
|
)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -195,7 +197,7 @@ async def apply_theme_preset(
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{vendor_code}")
|
@router.delete("/{vendor_code}", response_model=ThemeDeleteResponse)
|
||||||
async def delete_vendor_theme(
|
async def delete_vendor_theme(
|
||||||
vendor_code: str = Path(..., description="Vendor code"),
|
vendor_code: str = Path(..., description="Vendor code"),
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
@@ -224,4 +226,4 @@ async def delete_vendor_theme(
|
|||||||
# Service handles deletion and raises exceptions if needed
|
# Service handles deletion and raises exceptions if needed
|
||||||
# Global exception handler converts them to proper HTTP responses
|
# Global exception handler converts them to proper HTTP responses
|
||||||
result = vendor_theme_service.delete_theme(db, vendor_code)
|
result = vendor_theme_service.delete_theme(db, vendor_code)
|
||||||
return result
|
return ThemeDeleteResponse(message=result.get("message", "Theme deleted successfully"))
|
||||||
|
|||||||
@@ -100,3 +100,9 @@ class ThemePresetListResponse(BaseModel):
|
|||||||
"""List of available theme presets."""
|
"""List of available theme presets."""
|
||||||
|
|
||||||
presets: list[ThemePresetPreview] = Field(..., description="Available presets")
|
presets: list[ThemePresetPreview] = Field(..., description="Available presets")
|
||||||
|
|
||||||
|
|
||||||
|
class ThemeDeleteResponse(BaseModel):
|
||||||
|
"""Response after deleting a theme."""
|
||||||
|
|
||||||
|
message: str = Field(..., description="Success message")
|
||||||
|
|||||||
Reference in New Issue
Block a user