From add86d7d83b10096f8dce8db03e486ab27152187 Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Sun, 8 Dec 2024 17:00:37 +0700 Subject: [PATCH] feat: add feature update user and update password --- dto/user.go | 71 ++++++++++++++++++++++++++--- internal/api/routes.go | 2 + internal/controllers/auth.go | 84 ++++++++++++++++++++++++++++++++++- internal/repositories/auth.go | 23 ++++++++++ internal/services/auth.go | 73 +++++++++++++++++++++++++++++- 5 files changed, 243 insertions(+), 10 deletions(-) diff --git a/dto/user.go b/dto/user.go index 1873fee..38664ef 100644 --- a/dto/user.go +++ b/dto/user.go @@ -44,12 +44,13 @@ func ValidatePassword(password string) error { } type RegisterUserInput struct { - Username string `json:"username"` - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - Password string `json:"password"` - RoleId string `json:"roleId"` + Username string `json:"username"` + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + Password string `json:"password"` + ConfirmPassword string `json:"confirm_password"` + RoleId string `json:"roleId"` } func (input *RegisterUserInput) Validate() error { @@ -74,9 +75,67 @@ func (input *RegisterUserInput) Validate() error { return err } + if input.Password != input.ConfirmPassword { + return errors.New("password dan confirm password tidak cocok") + } + if input.RoleId == "" { return errors.New("roleId harus diisi") } return nil } + +type UpdatePasswordInput struct { + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` +} + +func (input *UpdatePasswordInput) Validate() error { + + if input.OldPassword == "" { + return errors.New("old password must be provided") + } + + if input.NewPassword == "" { + return errors.New("new password must be provided") + } + + if len(input.NewPassword) < 8 { + return errors.New("new password must be at least 8 characters long") + } + + return nil +} + +type UpdateUserInput struct { + Email string `json:"email"` + Username string `json:"username"` + Name string `json:"name"` + Phone string `json:"phone"` +} + +func (input *UpdateUserInput) Validate() error { + + if input.Email != "" { + if err := ValidateEmail(input.Email); err != nil { + return err + } + } + + if input.Username == "" { + return errors.New("username harus diisi") + } + + if input.Name == "" { + return errors.New("name harus diisi") + } + + if input.Phone != "" { + if err := ValidatePhone(input.Phone); err != nil { + return err + } + } + + return nil +} diff --git a/internal/api/routes.go b/internal/api/routes.go index 2f58b82..c139877 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -11,6 +11,8 @@ func AppRouter(app *fiber.App) { app.Post("/login", controllers.Login) app.Get("/user", middleware.AuthMiddleware, controllers.GetUserInfo) + app.Put("/update-user", middleware.AuthMiddleware, controllers.UpdateUser) + app.Post("/user/update-password", middleware.AuthMiddleware, controllers.UpdatePassword) app.Get("/list-address", middleware.AuthMiddleware, controllers.GetListAddress) app.Get("/address/:id", middleware.AuthMiddleware, controllers.GetAddressByID) diff --git a/internal/controllers/auth.go b/internal/controllers/auth.go index 06eb87c..dafb4b0 100644 --- a/internal/controllers/auth.go +++ b/internal/controllers/auth.go @@ -27,9 +27,8 @@ func Register(c *fiber.Ctx) error { )) } - err := services.RegisterUser(userInput.Username, userInput.Name, userInput.Email, userInput.Phone, userInput.Password, userInput.RoleId) + err := services.RegisterUser(userInput.Username, userInput.Name, userInput.Email, userInput.Phone, userInput.Password, userInput.ConfirmPassword, userInput.RoleId) if err != nil { - if err.Error() == "email is already registered" { return c.Status(fiber.StatusConflict).JSON(utils.FormatResponse( fiber.StatusConflict, @@ -51,6 +50,13 @@ func Register(c *fiber.Ctx) error { nil, )) } + if err.Error() == "password dan confirm password tidak cocok" { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Password dan confirm password tidak cocok", + nil, + )) + } return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( fiber.StatusInternalServerError, @@ -149,3 +155,77 @@ func GetUserInfo(c *fiber.Ctx) error { userResponse, )) } + +func UpdateUser(c *fiber.Ctx) error { + var userInput dto.UpdateUserInput + + if err := c.BodyParser(&userInput); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid input data", + nil, + )) + } + + if err := userInput.Validate(); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + err.Error(), + nil, + )) + } + + userID := c.Locals("userID").(string) + + err := services.UpdateUser(userID, userInput.Email, userInput.Username, userInput.Name, userInput.Phone) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + err.Error(), + nil, + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "User updated successfully", + nil, + )) +} + +func UpdatePassword(c *fiber.Ctx) error { + var passwordInput dto.UpdatePasswordInput + + if err := c.BodyParser(&passwordInput); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + "Invalid input data", + nil, + )) + } + + if err := passwordInput.Validate(); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse( + fiber.StatusBadRequest, + err.Error(), + nil, + )) + } + + userID := c.Locals("userID").(string) + + err := services.UpdatePassword(userID, passwordInput.OldPassword, passwordInput.NewPassword) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( + fiber.StatusInternalServerError, + err.Error(), + nil, + )) + } + + return c.Status(fiber.StatusOK).JSON(utils.FormatResponse( + fiber.StatusOK, + "Password updated successfully", + nil, + )) +} diff --git a/internal/repositories/auth.go b/internal/repositories/auth.go index d1d398e..f4c8767 100644 --- a/internal/repositories/auth.go +++ b/internal/repositories/auth.go @@ -83,3 +83,26 @@ func GetUserByID(userID string) (domain.User, error) { return user, nil } + +func UpdateUser(user *domain.User) error { + if err := config.DB.Save(user).Error; err != nil { + return errors.New("failed to save user") + } + return nil +} + +func UpdateUserPassword(userID, newPassword string) error { + var user domain.User + + if err := config.DB.Where("id = ?", userID).First(&user).Error; err != nil { + return errors.New("user not found") + } + + user.Password = newPassword + + if err := config.DB.Save(&user).Error; err != nil { + return errors.New("failed to update password") + } + + return nil +} diff --git a/internal/services/auth.go b/internal/services/auth.go index 6b30d3a..ce6f7fd 100644 --- a/internal/services/auth.go +++ b/internal/services/auth.go @@ -11,7 +11,10 @@ import ( "golang.org/x/crypto/bcrypt" ) -func RegisterUser(username, name, email, phone, password, roleId string) error { +func RegisterUser(username, name, email, phone, password, confirmPassword, roleId string) error { + if password != confirmPassword { + return errors.New("password dan confirm password tidak cocok") + } if repositories.IsEmailExist(email) { return errors.New("email is already registered") @@ -46,7 +49,8 @@ func LoginUser(emailOrUsername, password string) (string, error) { return "", errors.New("invalid email/username or password") } - if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) + if err != nil { return "", errors.New("invalid email/username or password") } @@ -78,3 +82,68 @@ func GetUserByID(userID string) (domain.User, error) { } return user, nil } + +func UpdateUser(userID, email, username, name, phone string) error { + + user, err := repositories.GetUserByID(userID) + if err != nil { + return errors.New("user not found") + } + + if email != "" && email != user.Email && repositories.IsEmailExist(email) { + return errors.New("email is already registered") + } + + if username != "" && username != user.Username && repositories.IsUsernameExist(username) { + return errors.New("username is already registered") + } + + if phone != "" && phone != user.Phone && repositories.IsPhoneExist(phone) { + return errors.New("phone number is already registered") + } + + if email != "" { + user.Email = email + } + if username != "" { + user.Username = username + } + if name != "" { + user.Name = name + } + if phone != "" { + user.Phone = phone + } + + err = repositories.UpdateUser(&user) + if err != nil { + return errors.New("failed to update user") + } + + return nil +} + +func UpdatePassword(userID, oldPassword, newPassword string) error { + + user, err := repositories.GetUserByID(userID) + if err != nil { + return errors.New("user not found") + } + + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)) + if err != nil { + return errors.New("old password is incorrect") + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) + if err != nil { + return errors.New("failed to hash new password") + } + + err = repositories.UpdateUserPassword(userID, string(hashedPassword)) + if err != nil { + return errors.New("failed to update password") + } + + return nil +}