fix: resolve all architecture validation errors (62 -> 0)
Major refactoring to achieve zero architecture violations: API Layer: - vendor/settings.py: Move validation to Pydantic field validators (tax rate, delivery method, boost sort, preorder days, languages, locales) - admin/email_templates.py: Add Pydantic response models (TemplateListResponse, CategoriesResponse) - shop/auth.py: Move password reset logic to CustomerService Service Layer: - customer_service.py: Add password reset methods (get_customer_for_password_reset, validate_and_reset_password) Exception Layer: - customer.py: Add InvalidPasswordResetTokenException, PasswordTooShortException Frontend: - admin/email-templates.js: Use apiClient, Utils.showToast() - vendor/email-templates.js: Use apiClient, parent init pattern Templates: - admin/email-templates.html: Fix block name to extra_scripts - shop/base.html: Add language default filter Tooling: - validate_architecture.py: Fix LANG-001 false positive for SUPPORTED_LANGUAGES and SUPPORTED_LOCALES blocks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,10 +19,13 @@ from app.exceptions.customer import (
|
||||
CustomerValidationException,
|
||||
DuplicateCustomerEmailException,
|
||||
InvalidCustomerCredentialsException,
|
||||
InvalidPasswordResetTokenException,
|
||||
PasswordTooShortException,
|
||||
)
|
||||
from app.exceptions.vendor import VendorNotActiveException, VendorNotFoundException
|
||||
from app.services.auth_service import AuthService
|
||||
from models.database.customer import Customer
|
||||
from models.database.password_reset_token import PasswordResetToken
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.auth import UserLogin
|
||||
from models.schema.customer import CustomerRegister, CustomerUpdate
|
||||
@@ -410,6 +413,88 @@ class CustomerService:
|
||||
|
||||
return customer_number
|
||||
|
||||
def get_customer_for_password_reset(
|
||||
self, db: Session, vendor_id: int, email: str
|
||||
) -> Customer | None:
|
||||
"""
|
||||
Get active customer by email for password reset.
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
vendor_id: Vendor ID
|
||||
email: Customer email
|
||||
|
||||
Returns:
|
||||
Customer if found and active, None otherwise
|
||||
"""
|
||||
return (
|
||||
db.query(Customer)
|
||||
.filter(
|
||||
Customer.vendor_id == vendor_id,
|
||||
Customer.email == email.lower(),
|
||||
Customer.is_active == True, # noqa: E712
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
def validate_and_reset_password(
|
||||
self,
|
||||
db: Session,
|
||||
vendor_id: int,
|
||||
reset_token: str,
|
||||
new_password: str,
|
||||
) -> Customer:
|
||||
"""
|
||||
Validate reset token and update customer password.
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
vendor_id: Vendor ID
|
||||
reset_token: Password reset token from email
|
||||
new_password: New password
|
||||
|
||||
Returns:
|
||||
Customer: Updated customer
|
||||
|
||||
Raises:
|
||||
PasswordTooShortException: If password too short
|
||||
InvalidPasswordResetTokenException: If token invalid/expired
|
||||
CustomerNotActiveException: If customer not active
|
||||
"""
|
||||
# Validate password length
|
||||
if len(new_password) < 8:
|
||||
raise PasswordTooShortException(min_length=8)
|
||||
|
||||
# Find valid token
|
||||
token_record = PasswordResetToken.find_valid_token(db, reset_token)
|
||||
|
||||
if not token_record:
|
||||
raise InvalidPasswordResetTokenException()
|
||||
|
||||
# Get the customer and verify they belong to this vendor
|
||||
customer = (
|
||||
db.query(Customer)
|
||||
.filter(Customer.id == token_record.customer_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if not customer or customer.vendor_id != vendor_id:
|
||||
raise InvalidPasswordResetTokenException()
|
||||
|
||||
if not customer.is_active:
|
||||
raise CustomerNotActiveException(customer.email)
|
||||
|
||||
# Hash the new password and update customer
|
||||
hashed_password = self.auth_service.hash_password(new_password)
|
||||
customer.hashed_password = hashed_password
|
||||
|
||||
# Mark token as used
|
||||
token_record.mark_used(db)
|
||||
|
||||
logger.info(f"Password reset completed for customer {customer.id}")
|
||||
|
||||
return customer
|
||||
|
||||
|
||||
# Singleton instance
|
||||
customer_service = CustomerService()
|
||||
|
||||
Reference in New Issue
Block a user