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) CreatePasswordHandler(c *gin.Context) { requestUser, err := uc.Service.FromContext(c) if err != nil { utils.RespondWithError(c, err, "Couldn't get User from Request Context", http.StatusBadRequest, errors.Responses.Fields.General, errors.Responses.Keys.NoAuthToken) return } if !requestUser.IsAdmin() { utils.RespondWithError(c, errors.ErrNotAuthorized, "Requesting user not authorized to grant user access", http.StatusUnauthorized, errors.Responses.Fields.User, errors.Responses.Keys.Unauthorized) return } // Expected data from the user var input struct { User struct { ID uint `json:"id" binding:"required,numeric"` } `json:"user"` } if err := c.ShouldBindJSON(&input); err != nil { utils.HandleValidationError(c, err) return } // find user user, err := uc.Service.FromID(&input.User.ID) if err != nil { utils.RespondWithError(c, err, "couldn't get user by id", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.NotFound) return } // Deactivate user and reset Verification user.Status = constants.DisabledStatus v, err := user.SetVerification(constants.VerificationTypes.Password) if err != nil { utils.RespondWithError(c, err, "couldn't set verification", http.StatusInternalServerError, errors.Responses.Fields.User, errors.Responses.Keys.InternalServerError) return } if _, err := uc.Service.Update(user); err != nil { utils.RespondWithError(c, err, "Couldn't update user in createPasswordHandler", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError) return } // send email if err := uc.EmailService.SendGrantBackendAccessEmail(user, &v.VerificationToken); err != nil { utils.RespondWithError(c, err, "Couldn't send grant backend access 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) 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 user, err := uc.Service.FromEmail(&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 !user.IsVerified() { utils.RespondWithError(c, errors.ErrNotAuthorized, "User password change request denied, user is not verified or disabled", http.StatusForbidden, errors.Responses.Fields.Login, errors.Responses.Keys.UserDisabled) return } user.Status = constants.DisabledStatus v, err := user.SetVerification(constants.VerificationTypes.Password) if err != nil { utils.RespondWithError(c, err, "couldn't set verification", http.StatusInternalServerError, errors.Responses.Fields.User, errors.Responses.Keys.InternalServerError) return } if _, err := uc.Service.Update(user); err != nil { utils.RespondWithError(c, err, "Couldn't update user in createPasswordHandler", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError) return } // send email if err := uc.EmailService.SendChangePasswordEmail(user, &v.VerificationToken); 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 } userID := uint(userIDint) user, err := uc.Service.FromID(&userID) if err != nil { utils.RespondWithError(c, err, "Couldn't find user", http.StatusNotFound, errors.Responses.Fields.User, errors.Responses.Keys.UserNotFoundWrongPassword) return } if err := c.ShouldBindJSON(&input); err != nil { utils.HandleValidationError(c, err) return } err = user.Verify(input.Token, constants.VerificationTypes.Password) if err != nil { utils.RespondWithError(c, err, "Couldn't verify user", http.StatusInternalServerError, errors.Responses.Fields.General, errors.Responses.Keys.InternalServerError) return } user.Status = constants.ActiveStatus 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.Update(user) if err != nil { utils.HandleUserUpdateError(c, err) return } c.JSON(http.StatusOK, gin.H{ "message": "password_changed", }) }