package controllers import ( "GoMembership/internal/constants" "GoMembership/internal/utils" "GoMembership/pkg/errors" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" ) func (uc *UserController) RequestPasswordChangeHandler(c *gin.Context) { // Expected data from the user var input struct { Email string `json:"email" binding:"required,email"` } if err := c.ShouldBindJSON(&input); err != nil { utils.HandleValidationError(c, err) return } // find user db_user, err := uc.Service.GetUserByEmail(input.Email) if err != nil { utils.RespondWithError(c, err, "couldn't get user by email", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound) return } // check if user may change the password if db_user.Status <= constants.DisabledStatus { utils.RespondWithError(c, errors.ErrNotAuthorized, "User password change request denied, user is disabled", http.StatusForbidden, errors.Responses.Fields.Login, errors.Responses.Keys.UserDisabled) return } // create token token, err := uc.Service.HandlePasswordChangeRequest(db_user) if err != nil { utils.RespondWithError(c, err, "couldn't handle password change request", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError) return } // send email if err := uc.EmailService.SendChangePasswordEmail(db_user, &token); err != nil { utils.RespondWithError(c, err, "Couldn't send change password email", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError) return } c.JSON(http.StatusAccepted, gin.H{ "message": "password_change_requested", }) } func (uc *UserController) ChangePassword(c *gin.Context) { // Expected data from the user var input struct { Password string `json:"password" binding:"required"` Token string `json:"token" binding:"required"` } userIDint, err := strconv.Atoi(c.Param("id")) if err != nil { utils.RespondWithError(c, err, "Invalid user ID", http.StatusBadRequest, errors.Responses.Fields.User, errors.Responses.Keys.InvalidUserID) return } if err := c.ShouldBindJSON(&input); err != nil { utils.HandleValidationError(c, err) return } verification, err := uc.Service.VerifyUser(&input.Token, &constants.VerificationTypes.Password) if err != nil || uint(userIDint) != verification.UserID { utils.HandleVerifyUserError(c, err) return } user, err := uc.Service.GetUserByID(verification.UserID) if err != nil { utils.RespondWithError(c, err, "Couldn't find user", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.UserNotFoundWrongPassword) return } user.Status = constants.ActiveStatus user.Verification = *verification user.ID = verification.UserID user.Password = input.Password // Get Gin's binding validator engine with all registered validators validate := binding.Validator.Engine().(*validator.Validate) // Validate the populated user struct if err := validate.Struct(user); err != nil { utils.HandleValidationError(c, err) return } _, err = uc.Service.UpdateUser(user) if err != nil { utils.HandleUserUpdateError(c, err) return } c.JSON(http.StatusOK, gin.H{ "message": "password_changed", }) }