# app/api/v1/shop/profile.py """ Shop Profile API (Customer authenticated) Endpoints for managing customer profile in shop frontend. Requires customer authentication. """ import logging from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from app.api.deps import get_current_customer_api from app.core.database import get_db from app.exceptions import ValidationException from app.services.auth_service import AuthService from app.services.customer_service import customer_service from models.database.customer import Customer from models.schema.customer import ( CustomerPasswordChange, CustomerResponse, CustomerUpdate, ) # Auth service for password operations auth_service = AuthService() router = APIRouter() logger = logging.getLogger(__name__) @router.get("/profile", response_model=CustomerResponse) # authenticated def get_profile( customer: Customer = Depends(get_current_customer_api), db: Session = Depends(get_db), ): """ Get current customer profile. Returns the authenticated customer's profile information. """ logger.debug( f"[SHOP_API] get_profile for customer {customer.id}", extra={ "customer_id": customer.id, "email": customer.email, }, ) return CustomerResponse.model_validate(customer) @router.put("/profile", response_model=CustomerResponse) def update_profile( update_data: CustomerUpdate, customer: Customer = Depends(get_current_customer_api), db: Session = Depends(get_db), ): """ Update current customer profile. Allows updating profile fields like name, phone, marketing consent, etc. Email changes require the new email to be unique within the vendor. Request Body: - email: New email address (optional) - first_name: First name (optional) - last_name: Last name (optional) - phone: Phone number (optional) - marketing_consent: Marketing consent (optional) - preferred_language: Preferred language (optional) """ logger.debug( f"[SHOP_API] update_profile for customer {customer.id}", extra={ "customer_id": customer.id, "email": customer.email, "update_fields": [k for k, v in update_data.model_dump().items() if v is not None], }, ) # If email is being changed, check uniqueness within vendor if update_data.email and update_data.email != customer.email: existing = customer_service.get_customer_by_email( db, customer.vendor_id, update_data.email ) if existing and existing.id != customer.id: raise ValidationException("Email already in use") # Update only provided fields update_dict = update_data.model_dump(exclude_unset=True) for field, value in update_dict.items(): if value is not None: setattr(customer, field, value) db.commit() db.refresh(customer) logger.info( f"Customer {customer.id} updated profile", extra={ "customer_id": customer.id, "updated_fields": list(update_dict.keys()), }, ) return CustomerResponse.model_validate(customer) @router.put("/profile/password", response_model=dict) def change_password( password_data: CustomerPasswordChange, customer: Customer = Depends(get_current_customer_api), db: Session = Depends(get_db), ): """ Change customer password. Requires current password verification and matching new password confirmation. Request Body: - current_password: Current password - new_password: New password (min 8 chars, must contain letter and digit) - confirm_password: Confirmation of new password """ logger.debug( f"[SHOP_API] change_password for customer {customer.id}", extra={ "customer_id": customer.id, "email": customer.email, }, ) # Verify current password if not auth_service.auth_manager.verify_password( password_data.current_password, customer.hashed_password ): raise ValidationException("Current password is incorrect") # Verify passwords match if password_data.new_password != password_data.confirm_password: raise ValidationException("New passwords do not match") # Check new password is different if password_data.new_password == password_data.current_password: raise ValidationException("New password must be different from current password") # Update password customer.hashed_password = auth_service.hash_password(password_data.new_password) db.commit() logger.info( f"Customer {customer.id} changed password", extra={ "customer_id": customer.id, "email": customer.email, }, ) return {"message": "Password changed successfully"}