refactor: enforce strict architecture rules and add Pydantic response models

- Update architecture rules to be stricter (API-003 now blocks ALL exception
  raising in endpoints, not just HTTPException)
- Update get_current_vendor_api dependency to guarantee token_vendor_id presence
- Remove redundant _get_vendor_from_token helpers from all vendor API files
- Move vendor access validation to service layer methods
- Add Pydantic response models for media, notification, and payment endpoints
- Add get_active_vendor_by_code service method for public vendor lookup
- Add get_import_job_for_vendor service method with vendor validation
- Update validation script to detect exception raising patterns in endpoints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-04 23:26:03 +01:00
parent cbfbbb4654
commit 81bfc49f77
25 changed files with 1225 additions and 530 deletions

View File

@@ -275,7 +275,9 @@ def get_current_vendor_api(
Get current vendor user from Authorization header ONLY.
Used for vendor API endpoints that should not accept cookies.
Validates that user still has access to the vendor specified in the token.
Validates that:
1. Token contains vendor context (token_vendor_id)
2. User still has access to the vendor specified in the token
Args:
credentials: Bearer token from Authorization header
@@ -285,7 +287,7 @@ def get_current_vendor_api(
User: Authenticated vendor user (with token_vendor_id, token_vendor_code, token_vendor_role)
Raises:
InvalidTokenException: If no token or invalid token
InvalidTokenException: If no token, invalid token, or missing vendor context
InsufficientPermissionsException: If user is not vendor or lost access to vendor
"""
if not credentials:
@@ -302,23 +304,25 @@ def get_current_vendor_api(
logger.warning(f"Non-vendor user {user.username} attempted vendor API")
raise InsufficientPermissionsException("Vendor privileges required")
# Validate vendor access if token is vendor-scoped
if hasattr(user, "token_vendor_id"):
vendor_id = user.token_vendor_id
# Require vendor context in token
if not hasattr(user, "token_vendor_id"):
raise InvalidTokenException("Token missing vendor information. Please login again.")
# Verify user still has access to this vendor
if not user.is_member_of(vendor_id):
logger.warning(
f"User {user.username} lost access to vendor_id={vendor_id}"
)
raise InsufficientPermissionsException(
"Access to vendor has been revoked. Please login again."
)
vendor_id = user.token_vendor_id
logger.debug(
f"Vendor API access: user={user.username}, vendor_id={vendor_id}, "
f"vendor_code={getattr(user, 'token_vendor_code', 'N/A')}"
# Verify user still has access to this vendor
if not user.is_member_of(vendor_id):
logger.warning(
f"User {user.username} lost access to vendor_id={vendor_id}"
)
raise InsufficientPermissionsException(
"Access to vendor has been revoked. Please login again."
)
logger.debug(
f"Vendor API access: user={user.username}, vendor_id={vendor_id}, "
f"vendor_code={getattr(user, 'token_vendor_code', 'N/A')}"
)
return user