diff --git a/dto/userpin_dto.go b/dto/userpin_dto.go index d8e333a..146cc96 100644 --- a/dto/userpin_dto.go +++ b/dto/userpin_dto.go @@ -1,18 +1,11 @@ package dto import ( + "fmt" "regexp" "strings" ) -type UserPinResponseDTO struct { - ID string `json:"id"` - UserID string `json:"userId"` - Pin string `json:"userpin"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` -} - type RequestUserPinDTO struct { Pin string `json:"userpin"` } @@ -24,10 +17,8 @@ func (r *RequestUserPinDTO) Validate() (map[string][]string, bool) { errors["pin"] = append(errors["pin"], "Pin is required") } - if len(r.Pin) != 6 { - errors["pin"] = append(errors["pin"], "Pin harus terdiri dari 6 digit") - } else if !isNumeric(r.Pin) { - errors["pin"] = append(errors["pin"], "Pin harus berupa angka") + if err := validatePin(r.Pin); err != nil { + errors["pin"] = append(errors["pin"], err.Error()) } if len(errors) > 0 { @@ -42,17 +33,15 @@ type UpdateUserPinDTO struct { NewPin string `json:"new_pin"` } -func (r *UpdateUserPinDTO) Validate() (map[string][]string, bool) { +func (u *UpdateUserPinDTO) Validate() (map[string][]string, bool) { errors := make(map[string][]string) - if strings.TrimSpace(r.OldPin) == "" { + if strings.TrimSpace(u.OldPin) == "" { errors["old_pin"] = append(errors["old_pin"], "Old pin is required") } - if strings.TrimSpace(r.NewPin) == "" { - errors["new_pin"] = append(errors["new_pin"], "New pin is required") - } else if len(r.NewPin) < 6 { - errors["new_pin"] = append(errors["new_pin"], "New pin must be at least 6 digits") + if err := validatePin(u.NewPin); err != nil { + errors["new_pin"] = append(errors["new_pin"], err.Error()) } if len(errors) > 0 { @@ -66,3 +55,12 @@ func isNumeric(s string) bool { re := regexp.MustCompile(`^[0-9]+$`) return re.MatchString(s) } + +func validatePin(pin string) error { + if len(pin) != 6 { + return fmt.Errorf("pin harus terdiri dari 6 digit") + } else if !isNumeric(pin) { + return fmt.Errorf("pin harus berupa angka") + } + return nil +} diff --git a/internal/handler/userpin_handler.go b/internal/handler/userpin_handler.go index 70f7853..cc5b599 100644 --- a/internal/handler/userpin_handler.go +++ b/internal/handler/userpin_handler.go @@ -21,6 +21,7 @@ func (h *UserPinHandler) VerifyUserPin(c *fiber.Ctx) error { return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) } + // Validasi input pin errors, valid := requestUserPinDTO.Validate() if !valid { return utils.ValidationErrorResponse(c, errors) @@ -31,12 +32,12 @@ func (h *UserPinHandler) VerifyUserPin(c *fiber.Ctx) error { return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") } - _, err := h.UserPinService.VerifyUserPin(requestUserPinDTO.Pin, userID) + message, err := h.UserPinService.VerifyUserPin(userID, requestUserPinDTO.Pin) if err != nil { - return utils.GenericResponse(c, fiber.StatusUnauthorized, "pin yang anda masukkan salah") + return utils.GenericResponse(c, fiber.StatusUnauthorized, err.Error()) } - return utils.SuccessResponse(c, map[string]string{"data": "pin yang anda masukkan benar"}, "Pin verification successful") + return utils.GenericResponse(c, fiber.StatusOK, message) } func (h *UserPinHandler) CheckPinStatus(c *fiber.Ctx) error { @@ -45,16 +46,16 @@ func (h *UserPinHandler) CheckPinStatus(c *fiber.Ctx) error { return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") } - status, _, err := h.UserPinService.CheckPinStatus(userID) + status, err := h.UserPinService.CheckPinStatus(userID) if err != nil { return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error()) } if status == "Pin not created" { - return utils.GenericResponse(c, fiber.StatusBadRequest, "pin belum dibuat") + return utils.GenericResponse(c, fiber.StatusBadRequest, "Pin belum dibuat") } - return utils.SuccessResponse(c, map[string]string{"data": "pin sudah dibuat"}, "Pin status retrieved successfully") + return utils.GenericResponse(c, fiber.StatusOK, "Pin sudah dibuat") } func (h *UserPinHandler) CreateUserPin(c *fiber.Ctx) error { @@ -70,12 +71,13 @@ func (h *UserPinHandler) CreateUserPin(c *fiber.Ctx) error { userID := c.Locals("userID").(string) - userPinResponse, err := h.UserPinService.CreateUserPin(userID, requestUserPinDTO.Pin) + message, err := h.UserPinService.CreateUserPin(userID, requestUserPinDTO.Pin) if err != nil { + return utils.GenericResponse(c, fiber.StatusConflict, err.Error()) } - return utils.CreateResponse(c, userPinResponse, "User pin created successfully") + return utils.GenericResponse(c, fiber.StatusCreated, message) } func (h *UserPinHandler) UpdateUserPin(c *fiber.Ctx) error { @@ -91,10 +93,10 @@ func (h *UserPinHandler) UpdateUserPin(c *fiber.Ctx) error { userID := c.Locals("userID").(string) - userPinResponse, err := h.UserPinService.UpdateUserPin(userID, requestUserPinDTO.OldPin, requestUserPinDTO.NewPin) + message, err := h.UserPinService.UpdateUserPin(userID, requestUserPinDTO.OldPin, requestUserPinDTO.NewPin) if err != nil { return utils.GenericResponse(c, fiber.StatusBadRequest, err.Error()) } - return utils.SuccessResponse(c, userPinResponse, "User pin updated successfully") + return utils.GenericResponse(c, fiber.StatusOK, message) } diff --git a/internal/repositories/userpin_repo.go b/internal/repositories/userpin_repo.go index 7c10f67..057964e 100644 --- a/internal/repositories/userpin_repo.go +++ b/internal/repositories/userpin_repo.go @@ -24,6 +24,10 @@ func (r *userPinRepository) FindByUserID(userID string) (*model.UserPin, error) var userPin model.UserPin err := r.DB.Where("user_id = ?", userID).First(&userPin).Error if err != nil { + if err == gorm.ErrRecordNotFound { + + return nil, nil + } return nil, err } return &userPin, nil @@ -52,4 +56,4 @@ func (r *userPinRepository) Update(userPin *model.UserPin) error { return err } return nil -} \ No newline at end of file +} diff --git a/internal/services/userpin_service.go b/internal/services/userpin_service.go index 240deb0..4324c17 100644 --- a/internal/services/userpin_service.go +++ b/internal/services/userpin_service.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/pahmiudahgede/senggoldong/dto" "github.com/pahmiudahgede/senggoldong/internal/repositories" "github.com/pahmiudahgede/senggoldong/model" "github.com/pahmiudahgede/senggoldong/utils" @@ -12,10 +11,10 @@ import ( ) type UserPinService interface { - CreateUserPin(userID, pin string) (*dto.UserPinResponseDTO, error) - VerifyUserPin(userID, pin string) (*dto.UserPinResponseDTO, error) - CheckPinStatus(userID string) (string, *dto.UserPinResponseDTO, error) - UpdateUserPin(userID, oldPin, newPin string) (*dto.UserPinResponseDTO, error) + CreateUserPin(userID, pin string) (string, error) + VerifyUserPin(userID, pin string) (string, error) + CheckPinStatus(userID string) (string, error) + UpdateUserPin(userID, oldPin, newPin string) (string, error) } type userPinService struct { @@ -26,62 +25,53 @@ func NewUserPinService(userPinRepo repositories.UserPinRepository) UserPinServic return &userPinService{UserPinRepo: userPinRepo} } -func (s *userPinService) VerifyUserPin(pin string, userID string) (*dto.UserPinResponseDTO, error) { +func (s *userPinService) VerifyUserPin(userID, pin string) (string, error) { + if pin == "" { + return "", fmt.Errorf("pin tidak boleh kosong") + } userPin, err := s.UserPinRepo.FindByUserID(userID) if err != nil { - return nil, fmt.Errorf("user pin not found") + return "", fmt.Errorf("error fetching user pin: %v", err) + } + if userPin == nil { + return "", fmt.Errorf("user pin not found") } err = bcrypt.CompareHashAndPassword([]byte(userPin.Pin), []byte(pin)) if err != nil { - return nil, fmt.Errorf("incorrect pin") + return "", fmt.Errorf("incorrect pin") } - createdAt, _ := utils.FormatDateToIndonesianFormat(userPin.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(userPin.UpdatedAt) - - userPinResponse := &dto.UserPinResponseDTO{ - ID: userPin.ID, - UserID: userPin.UserID, - Pin: userPin.Pin, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return userPinResponse, nil + return "Pin yang anda masukkan benar", nil } -func (s *userPinService) CheckPinStatus(userID string) (string, *dto.UserPinResponseDTO, error) { +func (s *userPinService) CheckPinStatus(userID string) (string, error) { userPin, err := s.UserPinRepo.FindByUserID(userID) if err != nil { - return "Pin not created", nil, nil + return "", fmt.Errorf("error checking pin status: %v", err) + } + if userPin == nil { + return "Pin not created", nil } - createdAt, _ := utils.FormatDateToIndonesianFormat(userPin.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(userPin.UpdatedAt) - - userPinResponse := &dto.UserPinResponseDTO{ - ID: userPin.ID, - UserID: userPin.UserID, - Pin: userPin.Pin, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } - - return "Pin already created", userPinResponse, nil + return "Pin already created", nil } -func (s *userPinService) CreateUserPin(userID, pin string) (*dto.UserPinResponseDTO, error) { +func (s *userPinService) CreateUserPin(userID, pin string) (string, error) { existingPin, err := s.UserPinRepo.FindByUserID(userID) - if err != nil && existingPin != nil { - return nil, fmt.Errorf("you have already created a pin, you don't need to create another one") + if err != nil { + return "", fmt.Errorf("error checking existing pin: %v", err) + } + + if existingPin != nil { + return "", fmt.Errorf("you have already created a pin, you don't need to create another one") } hashedPin, err := bcrypt.GenerateFromPassword([]byte(pin), bcrypt.DefaultCost) if err != nil { - return nil, fmt.Errorf("error hashing the pin: %v", err) + return "", fmt.Errorf("error hashing the pin: %v", err) } newPin := model.UserPin{ @@ -91,74 +81,52 @@ func (s *userPinService) CreateUserPin(userID, pin string) (*dto.UserPinResponse err = s.UserPinRepo.Create(&newPin) if err != nil { - return nil, fmt.Errorf("error creating user pin: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(newPin.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(newPin.UpdatedAt) - - userPinResponse := &dto.UserPinResponseDTO{ - ID: newPin.ID, - UserID: newPin.UserID, - Pin: newPin.Pin, - CreatedAt: createdAt, - UpdatedAt: updatedAt, + return "", fmt.Errorf("error creating user pin: %v", err) } cacheKey := fmt.Sprintf("userpin:%s", userID) - cacheData := map[string]interface{}{ - "data": userPinResponse, - } + cacheData := map[string]interface{}{"data": newPin} err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) if err != nil { fmt.Printf("Error caching new user pin to Redis: %v\n", err) } - return userPinResponse, nil + return "Pin berhasil dibuat", nil } -func (s *userPinService) UpdateUserPin(userID, oldPin, newPin string) (*dto.UserPinResponseDTO, error) { +func (s *userPinService) UpdateUserPin(userID, oldPin, newPin string) (string, error) { userPin, err := s.UserPinRepo.FindByUserID(userID) if err != nil { - return nil, fmt.Errorf("user pin not found") + return "", fmt.Errorf("error fetching user pin: %v", err) + } + + if userPin == nil { + return "", fmt.Errorf("user pin not found") } err = bcrypt.CompareHashAndPassword([]byte(userPin.Pin), []byte(oldPin)) if err != nil { - return nil, fmt.Errorf("incorrect old pin") + return "", fmt.Errorf("incorrect old pin") } hashedPin, err := bcrypt.GenerateFromPassword([]byte(newPin), bcrypt.DefaultCost) if err != nil { - return nil, fmt.Errorf("error hashing the new pin: %v", err) + return "", fmt.Errorf("error hashing the new pin: %v", err) } userPin.Pin = string(hashedPin) err = s.UserPinRepo.Update(userPin) if err != nil { - return nil, fmt.Errorf("error updating user pin: %v", err) - } - - createdAt, _ := utils.FormatDateToIndonesianFormat(userPin.CreatedAt) - updatedAt, _ := utils.FormatDateToIndonesianFormat(userPin.UpdatedAt) - - userPinResponse := &dto.UserPinResponseDTO{ - ID: userPin.ID, - UserID: userPin.UserID, - Pin: userPin.Pin, - CreatedAt: createdAt, - UpdatedAt: updatedAt, + return "", fmt.Errorf("error updating user pin: %v", err) } cacheKey := fmt.Sprintf("userpin:%s", userID) - cacheData := map[string]interface{}{ - "data": userPinResponse, - } + cacheData := map[string]interface{}{"data": userPin} err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24) if err != nil { fmt.Printf("Error caching updated user pin to Redis: %v\n", err) } - return userPinResponse, nil + return "Pin berhasil diperbarui", nil }