From cacd268fd67a5fda25b279518f2eff1c7563937e Mon Sep 17 00:00:00 2001 From: oleksandrkhmil Date: Fri, 9 May 2025 14:58:44 +0300 Subject: [PATCH 1/4] refactor: add error checking for user repository --- internal/repositories/user_repository.go | 23 +++++++++++++------- internal/server/handlers/auth_handler.go | 9 +++++--- internal/server/handlers/register_handler.go | 7 ++---- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go index 4c0a530..d8c6287 100644 --- a/internal/repositories/user_repository.go +++ b/internal/repositories/user_repository.go @@ -1,23 +1,30 @@ package repositories import ( + "errors" + "fmt" + "github.com/nix-united/golang-echo-boilerplate/internal/models" "gorm.io/gorm" ) -type UserRepositoryQ interface { - GetUserByEmail(user *models.User, email string) -} - type UserRepository struct { - DB *gorm.DB + db *gorm.DB } func NewUserRepository(db *gorm.DB) *UserRepository { - return &UserRepository{DB: db} + return &UserRepository{db: db} } -func (userRepository *UserRepository) GetUserByEmail(user *models.User, email string) { - userRepository.DB.Where("email = ?", email).Find(user) +func (r *UserRepository) GetUserByEmail(email string) (models.User, error) { + var user models.User + err := r.db.Where("email = ?", email).Take(&user).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return models.User{}, fmt.Errorf("user not found: %w", err) + } else if err != nil { + return models.User{}, fmt.Errorf("execute select user by email query: %w", err) + } + + return user, nil } diff --git a/internal/server/handlers/auth_handler.go b/internal/server/handlers/auth_handler.go index 6dcdad3..8a27ff2 100644 --- a/internal/server/handlers/auth_handler.go +++ b/internal/server/handlers/auth_handler.go @@ -47,11 +47,14 @@ func (authHandler *AuthHandler) Login(c echo.Context) error { return responses.ErrorResponse(c, http.StatusBadRequest, "Required fields are empty or not valid") } - user := models.User{} userRepository := repositories.NewUserRepository(authHandler.server.DB) - userRepository.GetUserByEmail(&user, loginRequest.Email) - if user.ID == 0 || (bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(loginRequest.Password)) != nil) { + user, err := userRepository.GetUserByEmail(loginRequest.Email) + if err != nil { + return responses.ErrorResponse(c, http.StatusNotFound, "User with such email not found: "+err.Error()) + } + + if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(loginRequest.Password)); err != nil { return responses.ErrorResponse(c, http.StatusUnauthorized, "Invalid credentials") } diff --git a/internal/server/handlers/register_handler.go b/internal/server/handlers/register_handler.go index a08b45c..db27962 100644 --- a/internal/server/handlers/register_handler.go +++ b/internal/server/handlers/register_handler.go @@ -3,7 +3,6 @@ package handlers import ( "net/http" - "github.com/nix-united/golang-echo-boilerplate/internal/models" "github.com/nix-united/golang-echo-boilerplate/internal/repositories" "github.com/nix-united/golang-echo-boilerplate/internal/requests" "github.com/nix-united/golang-echo-boilerplate/internal/responses" @@ -44,11 +43,9 @@ func (registerHandler *RegisterHandler) Register(c echo.Context) error { return responses.ErrorResponse(c, http.StatusBadRequest, "Required fields are empty or not valid") } - existUser := models.User{} userRepository := repositories.NewUserRepository(registerHandler.server.DB) - userRepository.GetUserByEmail(&existUser, registerRequest.Email) - - if existUser.ID != 0 { + _, err := userRepository.GetUserByEmail(registerRequest.Email) + if err == nil { return responses.ErrorResponse(c, http.StatusBadRequest, "User already exists") } From 6971fa0ab65b8050a0b42b126fb7b1a9281dd007 Mon Sep 17 00:00:00 2001 From: oleksandrkhmil Date: Fri, 9 May 2025 15:24:29 +0300 Subject: [PATCH 2/4] fix: unit tests --- internal/server/handlers/auth_handler.go | 2 +- tests/auth_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/server/handlers/auth_handler.go b/internal/server/handlers/auth_handler.go index 8a27ff2..3c2aa65 100644 --- a/internal/server/handlers/auth_handler.go +++ b/internal/server/handlers/auth_handler.go @@ -51,7 +51,7 @@ func (authHandler *AuthHandler) Login(c echo.Context) error { user, err := userRepository.GetUserByEmail(loginRequest.Email) if err != nil { - return responses.ErrorResponse(c, http.StatusNotFound, "User with such email not found: "+err.Error()) + return responses.ErrorResponse(c, http.StatusNotFound, "User with such email not found") } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(loginRequest.Password)); err != nil { diff --git a/tests/auth_test.go b/tests/auth_test.go index 4573382..62c22be 100644 --- a/tests/auth_test.go +++ b/tests/auth_test.go @@ -98,8 +98,8 @@ func TestWalkAuth(t *testing.T) { handlerFunc, []*helpers.QueryMock{&helpers.SelectVersionMock, commonMock}, helpers.ExpectedResponse{ - StatusCode: 401, - BodyPart: "Invalid credentials", + StatusCode: 404, + BodyPart: "User with such email not found", }, }, } From bd0f78da375c453f908a41bab1f4970963bd2939 Mon Sep 17 00:00:00 2001 From: oleksandrkhmil Date: Fri, 9 May 2025 15:33:36 +0300 Subject: [PATCH 3/4] feat: add user not found error --- internal/models/errors.go | 5 +++++ internal/repositories/user_repository.go | 7 ++++--- internal/server/handlers/auth_handler.go | 8 ++++++-- internal/server/handlers/register_handler.go | 10 ++++++++-- 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 internal/models/errors.go diff --git a/internal/models/errors.go b/internal/models/errors.go new file mode 100644 index 0000000..98c84ed --- /dev/null +++ b/internal/models/errors.go @@ -0,0 +1,5 @@ +package models + +import "errors" + +var ErrUserNotFound = errors.New("user not found") diff --git a/internal/repositories/user_repository.go b/internal/repositories/user_repository.go index d8c6287..48d1d16 100644 --- a/internal/repositories/user_repository.go +++ b/internal/repositories/user_repository.go @@ -1,6 +1,7 @@ package repositories import ( + "context" "errors" "fmt" @@ -17,11 +18,11 @@ func NewUserRepository(db *gorm.DB) *UserRepository { return &UserRepository{db: db} } -func (r *UserRepository) GetUserByEmail(email string) (models.User, error) { +func (r *UserRepository) GetUserByEmail(ctx context.Context, email string) (models.User, error) { var user models.User - err := r.db.Where("email = ?", email).Take(&user).Error + err := r.db.WithContext(ctx).Where("email = ?", email).Take(&user).Error if errors.Is(err, gorm.ErrRecordNotFound) { - return models.User{}, fmt.Errorf("user not found: %w", err) + return models.User{}, errors.Join(models.ErrUserNotFound, err) } else if err != nil { return models.User{}, fmt.Errorf("execute select user by email query: %w", err) } diff --git a/internal/server/handlers/auth_handler.go b/internal/server/handlers/auth_handler.go index 3c2aa65..48af709 100644 --- a/internal/server/handlers/auth_handler.go +++ b/internal/server/handlers/auth_handler.go @@ -1,6 +1,7 @@ package handlers import ( + "errors" "fmt" "net/http" @@ -49,10 +50,13 @@ func (authHandler *AuthHandler) Login(c echo.Context) error { userRepository := repositories.NewUserRepository(authHandler.server.DB) - user, err := userRepository.GetUserByEmail(loginRequest.Email) - if err != nil { + user, err := userRepository.GetUserByEmail(c.Request().Context(), loginRequest.Email) + if errors.Is(err, models.ErrUserNotFound) { return responses.ErrorResponse(c, http.StatusNotFound, "User with such email not found") } + if err != nil { + return responses.ErrorResponse(c, http.StatusInternalServerError, "Failed to get user by email") + } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(loginRequest.Password)); err != nil { return responses.ErrorResponse(c, http.StatusUnauthorized, "Invalid credentials") diff --git a/internal/server/handlers/register_handler.go b/internal/server/handlers/register_handler.go index db27962..22a72f8 100644 --- a/internal/server/handlers/register_handler.go +++ b/internal/server/handlers/register_handler.go @@ -1,8 +1,10 @@ package handlers import ( + "errors" "net/http" + "github.com/nix-united/golang-echo-boilerplate/internal/models" "github.com/nix-united/golang-echo-boilerplate/internal/repositories" "github.com/nix-united/golang-echo-boilerplate/internal/requests" "github.com/nix-united/golang-echo-boilerplate/internal/responses" @@ -44,9 +46,13 @@ func (registerHandler *RegisterHandler) Register(c echo.Context) error { } userRepository := repositories.NewUserRepository(registerHandler.server.DB) - _, err := userRepository.GetUserByEmail(registerRequest.Email) + + _, err := userRepository.GetUserByEmail(c.Request().Context(), registerRequest.Email) + if err != nil && !errors.Is(err, models.ErrUserNotFound) { + return responses.ErrorResponse(c, http.StatusInternalServerError, "Failed to check if user with such email exists") + } if err == nil { - return responses.ErrorResponse(c, http.StatusBadRequest, "User already exists") + return responses.ErrorResponse(c, http.StatusConflict, "User already exists") } userService := user.NewUserService(registerHandler.server.DB) From 1d235089620b324f4f6c8f1cb4deca5e782f8413 Mon Sep 17 00:00:00 2001 From: oleksandrkhmil Date: Fri, 9 May 2025 15:40:24 +0300 Subject: [PATCH 4/4] fix: unit tests --- tests/register_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/register_test.go b/tests/register_test.go index 7953791..ae55a4c 100644 --- a/tests/register_test.go +++ b/tests/register_test.go @@ -118,7 +118,7 @@ func TestWalkRegister(t *testing.T) { }, }, helpers.ExpectedResponse{ - StatusCode: 400, + StatusCode: 409, BodyPart: "User already exists", }, },