feat: Implement email change functionality

This commit introduces the following changes:

-   Added new API endpoints for email change requests and
    verification.
-   Updated the backend code to support email change workflow,
    including validation, code generation, and email sending.
-   Updated the frontend to include components for initiating and
    verifying email changes.
-   Added new dependencies to support email change functionality.
-   Updated the existing components to include email change
    functionality.

https://codeberg.org/mapleopentech/monorepo/issues/1
This commit is contained in:
Bartlomiej Mika 2025-12-05 15:29:26 -05:00
parent 480a2b557d
commit 598a7d3fad
19 changed files with 1213 additions and 65 deletions

View file

@ -132,24 +132,16 @@ func (svc *updateMeServiceImpl) Execute(sessCtx context.Context, req *UpdateMeRe
}
//
// Check if the requested email is already taken by another user.
// Block email changes - must use dedicated email change endpoint
// Note: Both emails are already lowercase (req.Email was lowercased in validation, user.Email is stored lowercase)
//
if req.Email != user.Email {
existingUser, err := svc.userGetByEmailUseCase.Execute(sessCtx, req.Email)
if err != nil {
svc.logger.Error("Failed checking existing email", zap.String("email", validation.MaskEmail(req.Email)), zap.Any("error", err))
return nil, err // Internal Server Error
}
if existingUser != nil {
// Email exists and belongs to another user.
svc.logger.Warn("Attempted to update to an email already in use",
zap.String("user_id", userID.String()),
zap.String("existing_user_id", existingUser.ID.String()),
zap.String("email", validation.MaskEmail(req.Email)))
e["email"] = "This email address is already in use."
return nil, httperror.NewForBadRequest(&e)
}
// If err is mongo.ErrNoDocuments or existingUser is nil, the email is available.
if strings.ToLower(req.Email) != strings.ToLower(user.Email) {
svc.logger.Warn("Attempted to change email via profile update",
zap.String("user_id", userID.String()),
zap.String("old_email", validation.MaskEmail(user.Email)),
zap.String("new_email", validation.MaskEmail(req.Email)))
e["email"] = "Email changes are not allowed through this endpoint. Please use the email change feature in your account settings."
return nil, httperror.NewForBadRequest(&e)
}
//
@ -157,7 +149,7 @@ func (svc *updateMeServiceImpl) Execute(sessCtx context.Context, req *UpdateMeRe
//
// Apply changes from request DTO to the user object
user.Email = req.Email
// NOTE: Email is NOT updated here - blocked above
user.FirstName = req.FirstName
user.LastName = req.LastName
user.Name = fmt.Sprintf("%s %s", req.FirstName, req.LastName)