From 02d75f0ab17c171501d0bbc017099e38a4be6573 Mon Sep 17 00:00:00 2001 From: Alex <$(pass /github/email)> Date: Wed, 9 Oct 2024 18:08:33 +0200 Subject: [PATCH] chg: backend: error struct --- internal/controllers/XSS_test.go | 2 +- internal/controllers/controllers_test.go | 38 +++- internal/controllers/membershipController.go | 1 + .../controllers/membershipController_test.go | 8 +- internal/controllers/user_controller.go | 167 ++++++++++++++---- internal/controllers/user_controller_test.go | 121 +++++++++---- internal/middlewares/auth.go | 12 +- 7 files changed, 275 insertions(+), 74 deletions(-) diff --git a/internal/controllers/XSS_test.go b/internal/controllers/XSS_test.go index 14cbdf4..ed9572a 100644 --- a/internal/controllers/XSS_test.go +++ b/internal/controllers/XSS_test.go @@ -26,6 +26,6 @@ func testXSSAttempt(t *testing.T) { w := httptest.NewRecorder() router.ServeHTTP(w, req) - assert.Equal(t, http.StatusNotAcceptable, w.Code) + assert.Equal(t, http.StatusBadRequest, w.Code) assert.NotContains(t, w.Body.String(), xssPayload) } diff --git a/internal/controllers/controllers_test.go b/internal/controllers/controllers_test.go index 1e28b2b..c629eaf 100644 --- a/internal/controllers/controllers_test.go +++ b/internal/controllers/controllers_test.go @@ -22,6 +22,7 @@ import ( "GoMembership/internal/repositories" "GoMembership/internal/services" "GoMembership/internal/utils" + "GoMembership/internal/validation" "GoMembership/pkg/logger" ) @@ -102,7 +103,9 @@ func TestSuite(t *testing.T) { var userRepo repositories.UserRepositoryInterface = &repositories.UserRepository{} userService := &services.UserService{Repo: userRepo, Licences: licenceRepo} - Uc = &UserController{Service: userService, EmailService: emailService, ConsentService: consentService, BankAccountService: bankAccountService, MembershipService: membershipService} + driversLicenceService := &services.DriversLicenceService{Repo: licenceRepo} + + Uc = &UserController{Service: userService, DriversLicenceService: driversLicenceService, EmailService: emailService, ConsentService: consentService, BankAccountService: bankAccountService, MembershipService: membershipService} Mc = &MembershipController{Service: *membershipService} Cc = &ContactController{EmailService: emailService} @@ -110,6 +113,10 @@ func TestSuite(t *testing.T) { log.Fatalf("Failed to init Subscription plans: %#v", err) } + if err := initLicenceCategories(); err != nil { + log.Fatalf("Failed to init Categories: %v", err) + } + validation.SetupValidators() t.Run("userController", func(t *testing.T) { testUserController(t) }) @@ -139,6 +146,35 @@ func TestSuite(t *testing.T) { // } } +func initLicenceCategories() error { + categories := []models.LicenceCategory{ + {Category: "AM"}, + {Category: "A1"}, + {Category: "A2"}, + {Category: "A"}, + {Category: "B"}, + {Category: "C1"}, + {Category: "C"}, + {Category: "D1"}, + {Category: "D"}, + {Category: "BE"}, + {Category: "C1E"}, + {Category: "CE"}, + {Category: "D1E"}, + {Category: "DE"}, + {Category: "T"}, + {Category: "L"}, + } + for _, category := range categories { + result := database.DB.Create(&category) + if result.Error != nil { + return result.Error + } + } + + return nil +} + func initSubscriptionPlans() error { subscriptions := []models.SubscriptionModel{ { diff --git a/internal/controllers/membershipController.go b/internal/controllers/membershipController.go index 30d72ad..ef9a48b 100644 --- a/internal/controllers/membershipController.go +++ b/internal/controllers/membershipController.go @@ -26,6 +26,7 @@ func (mc *MembershipController) RegisterSubscription(c *gin.Context) { if err := c.ShouldBindJSON(®Data); err != nil { logger.Error.Printf("Couln't decode subscription data: %v", err) c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode subscription data"}) + return } // Register Subscription diff --git a/internal/controllers/membershipController_test.go b/internal/controllers/membershipController_test.go index be1c318..867c8f0 100644 --- a/internal/controllers/membershipController_test.go +++ b/internal/controllers/membershipController_test.go @@ -86,7 +86,7 @@ func getSubscriptionData() []RegisterSubscriptionTest { return []RegisterSubscriptionTest{ { Name: "Missing details should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": "Just a Subscription"}, Assert: false, Input: GenerateInputJSON( @@ -97,7 +97,7 @@ func getSubscriptionData() []RegisterSubscriptionTest { }, { Name: "Missing model name should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": ""}, Assert: false, Input: GenerateInputJSON( @@ -108,7 +108,7 @@ func getSubscriptionData() []RegisterSubscriptionTest { }, { Name: "Negative monthly fee should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": "Premium"}, Assert: false, Input: GenerateInputJSON(customizeSubscription(func(sub MembershipData) MembershipData { @@ -118,7 +118,7 @@ func getSubscriptionData() []RegisterSubscriptionTest { }, { Name: "Negative hourly rate should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"name": "Premium"}, Assert: false, Input: GenerateInputJSON(customizeSubscription(func(sub MembershipData) MembershipData { diff --git a/internal/controllers/user_controller.go b/internal/controllers/user_controller.go index 36ecbc1..8bb669d 100644 --- a/internal/controllers/user_controller.go +++ b/internal/controllers/user_controller.go @@ -7,10 +7,12 @@ import ( "GoMembership/internal/models" "GoMembership/internal/services" "GoMembership/internal/utils" + "strings" "net/http" "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" "GoMembership/pkg/errors" "GoMembership/pkg/logger" @@ -33,13 +35,34 @@ func (uc *UserController) UpdateHandler(c *gin.Context) { var user models.User if err := c.ShouldBindJSON(&user); err != nil { logger.Error.Printf("Couldn't decode input: %v", err) - c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode request data"}) + var validationErrors []gin.H + if ve, ok := err.(validator.ValidationErrors); ok { + for _, e := range ve { + + validationErrors = append(validationErrors, gin.H{ + "field": e.Field(), + "key": "server.validation." + e.Tag(), + }) + } + } else { + validationErrors = append(validationErrors, gin.H{ + "field": "general", + "key": "server.error.invalid_json", + }) + } + logger.Error.Printf("ValidationErrors: %#v", validationErrors) + c.JSON(http.StatusBadRequest, gin.H{"errors": validationErrors}) + c.Abort() return } + logger.Error.Print("Continuing...") tokenString, err := c.Cookie("jwt") if err != nil { logger.Error.Printf("No Auth token: %v\n", err) - c.JSON(http.StatusUnauthorized, gin.H{"error": "No Auth token"}) + c.JSON(http.StatusUnauthorized, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.no_auth_token", + }}}) c.Abort() return } @@ -47,7 +70,10 @@ func (uc *UserController) UpdateHandler(c *gin.Context) { if err != nil { logger.Error.Printf("Error retrieving token and claims from JWT") - c.JSON(http.StatusInternalServerError, gin.H{"error": "JWT parsing error"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.jwt_parsing_error", + }}}) return } jwtUserID := uint((*claims)["user_id"].(float64)) @@ -55,22 +81,27 @@ func (uc *UserController) UpdateHandler(c *gin.Context) { if user.ID == 0 { logger.Error.Printf("No User.ID in request from user with id: %v, aborting", jwtUserID) - c.JSON(http.StatusBadRequest, gin.H{"error": "No user id provided"}) + c.JSON(http.StatusBadRequest, gin.H{"errors": []gin.H{{ + "field": "id", + "key": "server.validation.no_user_id_provided", + }}}) return } if user.ID != jwtUserID && userRole < constants.Roles.Editor { - c.JSON(http.StatusForbidden, gin.H{"error": "You are not authorized to update this user"}) - return - } - if user.Membership.SubscriptionModel.Name == "" { - logger.Error.Printf("No subscription model provided: %v", user.Email) - c.JSON(http.StatusNotAcceptable, gin.H{"error": "No subscription model provided"}) + c.JSON(http.StatusForbidden, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.unauthorized_update", + }}}) return } + selectedModel, err := uc.MembershipService.GetModelByName(&user.Membership.SubscriptionModel.Name) if err != nil { logger.Error.Printf("%v:No subscription model found: %#v", user.Email, err) - c.JSON(http.StatusNotFound, gin.H{"error": "Not a valid subscription model"}) + c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ + "field": "subscription_model", + "key": "server.validation.invalid_subscription_model", + }}}) return } user.Membership.SubscriptionModel = *selectedModel @@ -84,20 +115,28 @@ func (uc *UserController) UpdateHandler(c *gin.Context) { // user.Email = existingUser.Email // user.RoleID = existingUser.RoleID // } - updatedUser, err := uc.Service.UpdateUser(&user, userRole) if err != nil { switch err { case errors.ErrUserNotFound: - c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) + c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ + "field": user.FirstName + " " + user.LastName, + "key": "server.validation.user_not_found", + }}}) case errors.ErrInvalidUserData: - c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user data"}) + c.JSON(http.StatusBadRequest, gin.H{"errors": []gin.H{{ + "field": "user", + "key": "server.validation.invalid_user_data", + }}}) default: logger.Error.Printf("Failed to update user: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal Server error"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.internal_server_error", + }}}) + return } - return } c.JSON(http.StatusAccepted, gin.H{"message": "User updated successfully", "user": updatedUser}) } @@ -106,37 +145,51 @@ func (uc *UserController) CurrentUserHandler(c *gin.Context) { userIDInterface, ok := c.Get("user_id") if !ok || userIDInterface == nil { logger.Error.Printf("Error getting user_id from header") - c.JSON(http.StatusInternalServerError, gin.H{"error": "Missing or invalid user ID type"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.validation.no_user_id_provided", + }}}) return } userID, ok := userIDInterface.(uint) if !ok { logger.Error.Printf("Error: user_id is not of type uint") - c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user ID type"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "user", + "key": "server.error.internal_server_error", + }}}) return } user, err := uc.Service.GetUserByID(uint(userID)) if err != nil { logger.Error.Printf("Error retrieving valid user: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving user."}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.internal_server_error", + }}}) return } subscriptions, err := uc.MembershipService.GetSubscriptions(nil) if err != nil { logger.Error.Printf("Error retrieving subscriptions: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving subscriptions."}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "validation.internal_server_error", + }}}) return } licenceCategories, err := uc.DriversLicenceService.GetAllCategories() if err != nil { logger.Error.Printf("Error retrieving licence categories: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving licence categories."}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "validation.internal_server_error", + }}}) return } - logger.Error.Printf("licenceCategories: %#v", licenceCategories) c.JSON(http.StatusOK, gin.H{ "user": user.Safe(), "subscriptions": subscriptions, @@ -164,14 +217,20 @@ func (uc *UserController) LoginHandler(c *gin.Context) { if err := c.ShouldBindJSON(&input); err != nil { logger.Error.Printf("Couldn't decode input: %v", err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode request data"}) + c.JSON(http.StatusBadRequest, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.invalid_json", + }}}) return } user, err := uc.Service.GetUserByEmail(input.Email) if err != nil { logger.Error.Printf("Error during user(%v) retrieval: %v\n", input.Email, err) - c.JSON(http.StatusNotFound, gin.H{"error": "Couldn't find user"}) + c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ + "field": "login", + "key": "server.validation.user_not_found_or_wrong_password", + }}}) return } @@ -179,20 +238,29 @@ func (uc *UserController) LoginHandler(c *gin.Context) { if err != nil { logger.Error.Printf("Error during Password comparison: %v", err.Error()) - c.JSON(http.StatusInternalServerError, gin.H{"error": "couldn't calculate match"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.internal_server_error", + }}}) return } if !ok { logger.Error.Printf("Wrong Password: %v %v", user.FirstName, user.LastName) - c.JSON(http.StatusNotAcceptable, gin.H{"error": "Wrong Password"}) + c.JSON(http.StatusNotAcceptable, gin.H{"errors": []gin.H{{ + "field": "login", + "key": "server.validation.user_not_found_or_wrong_password", + }}}) return } logger.Error.Printf("jwtsevret: %v", config.Auth.JWTSecret) token, err := middlewares.GenerateToken(config.Auth.JWTSecret, user, "") if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate JWT token"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.jwt_generation_failed", + }}}) return } @@ -209,18 +277,31 @@ func (uc *UserController) RegisterUser(c *gin.Context) { if err := c.ShouldBindJSON(®Data); err != nil { logger.Error.Printf("Couldn't decode Userdata: %v", err) - c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode userdata"}) - return - } - if regData.User.Membership.SubscriptionModel.Name == "" { - logger.Error.Printf("No subscription model provided: %v", regData.User.Email) - c.JSON(http.StatusNotAcceptable, gin.H{"error": "No subscription model provided"}) + var validationErrors []gin.H + if ve, ok := err.(validator.ValidationErrors); ok { + for _, e := range ve { + validationErrors = append(validationErrors, gin.H{ + "field": e.Field(), + "key": "server.validation." + e.Tag(), + }) + } + } else { + validationErrors = append(validationErrors, gin.H{ + "field": "general", + "key": "server.error.invalid_json", + }) + } + c.JSON(http.StatusBadRequest, gin.H{"error": validationErrors}) return } + selectedModel, err := uc.MembershipService.GetModelByName(®Data.User.Membership.SubscriptionModel.Name) if err != nil { logger.Error.Printf("%v:No subscription model found: %#v", regData.User.Email, err) - c.JSON(http.StatusNotFound, gin.H{"error": "Not a valid subscription model"}) + c.JSON(http.StatusNotFound, gin.H{"errors": []gin.H{{ + "field": "subscription_model", + "key": "server.validation.invalid_subscription_model", + }}}) return } regData.User.Membership.SubscriptionModel = *selectedModel @@ -231,7 +312,18 @@ func (uc *UserController) RegisterUser(c *gin.Context) { id, token, err := uc.Service.RegisterUser(®Data.User) if err != nil { logger.Error.Printf("Couldn't register User(%v): %v", regData.User.Email, err) - c.JSON(int(id), gin.H{"error": "Couldn't register User"}) + if strings.Contains(err.Error(), "UNIQUE constraint failed: users.email") { + c.JSON(http.StatusConflict, gin.H{"errors": []gin.H{{ + "field": "email", + "key": "server.validation.email_already_registered", + }}}) + } else { + logger.Error.Printf("Failed to register user: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.internal_server_error", + }}}) + } return } regData.User.ID = id @@ -255,7 +347,10 @@ func (uc *UserController) RegisterUser(c *gin.Context) { _, err = uc.ConsentService.RegisterConsent(&consent) if err != nil { logger.Error.Printf("%v, Couldn't register consent: %v", regData.User.Email, err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-consent"}) + c.JSON(http.StatusInternalServerError, gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.internal_server_error", + }}}) return } } diff --git a/internal/controllers/user_controller_test.go b/internal/controllers/user_controller_test.go index edf3c48..e820fe6 100644 --- a/internal/controllers/user_controller_test.go +++ b/internal/controllers/user_controller_test.go @@ -243,6 +243,7 @@ func testCurrentUserHandler(t *testing.T, loginEmail string, loginCookie http.Co expectedUserMail string expectedStatus int expectNewCookie bool + expectedErrors []map[string]string }{ { name: "With valid cookie", @@ -274,6 +275,9 @@ func testCurrentUserHandler(t *testing.T, loginEmail string, loginCookie http.Co name: "Without cookie", setupCookie: func(req *http.Request) {}, expectedStatus: http.StatusUnauthorized, + expectedErrors: []map[string]string{ + {"field": "general", "key": "server.error.no_auth_token"}, + }, }, { name: "With invalid cookie", @@ -281,6 +285,9 @@ func testCurrentUserHandler(t *testing.T, loginEmail string, loginCookie http.Co req.AddCookie(&invalidCookie) }, expectedStatus: http.StatusUnauthorized, + expectedErrors: []map[string]string{ + {"field": "general", "key": "server.error.no_auth_token"}, + }, }, } @@ -327,12 +334,22 @@ func testCurrentUserHandler(t *testing.T, loginEmail string, loginCookie http.Co assert.Nil(t, newCookie, "No new cookie should be set for non-expired token") } } else { - // For unauthorized requests, check for an error message - var errorResponse map[string]string + // For unauthorized requests, check for the new error structure + var errorResponse map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &errorResponse) assert.NoError(t, err) - assert.Contains(t, errorResponse, "error") - assert.NotEmpty(t, errorResponse["error"]) + + errors, ok := errorResponse["errors"].([]interface{}) + assert.True(t, ok, "Expected 'errors' field in response") + assert.Len(t, errors, len(tt.expectedErrors), "Unexpected number of errors") + + for i, expectedError := range tt.expectedErrors { + if i < len(errors) { + actualError := errors[i].(map[string]interface{}) + assert.Equal(t, expectedError["field"], actualError["field"], "Mismatched error field") + assert.Equal(t, expectedError["key"], actualError["key"], "Mismatched error key") + } + } } }) @@ -414,7 +431,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { setupCookie func(*http.Request) updateFunc func(*models.User) expectedStatus int - expectedError string + expectedErrors []map[string]string }{ { name: "Valid Update", @@ -441,7 +458,9 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { u.Phone = "01738484994" }, expectedStatus: http.StatusUnauthorized, - expectedError: "Auth token invalid", + expectedErrors: []map[string]string{ + {"field": "general", "key": "server.error.no_auth_token"}, + }, }, { name: "Invalid Email Update", @@ -456,7 +475,9 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { u.Email = "invalid-email" }, expectedStatus: http.StatusBadRequest, - expectedError: "Invalid user data", + expectedErrors: []map[string]string{ + {"field": "Email", "key": "server.validation.email"}, + }, }, { name: "Change LicenceNumber", @@ -491,7 +512,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { expectedStatus: http.StatusAccepted, }, { - name: "Add 2 categories", + name: "Delete 1 and add 1 category", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, @@ -502,13 +523,31 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { u.Phone = "01738484994" u.DriversLicence.LicenceNumber = "B072RRE2I50" var licenceRepo repositories.DriversLicenceInterface = &repositories.DriversLicenceRepository{} - category, err := licenceRepo.FindCategoryByName("B") + category, err := licenceRepo.FindCategoryByName("A") category2, err := licenceRepo.FindCategoryByName("BE") assert.NoError(t, err) u.DriversLicence.LicenceCategories = []models.LicenceCategory{category, category2} }, expectedStatus: http.StatusAccepted, }, + { + name: "Delete 1 category", + setupCookie: func(req *http.Request) { + req.AddCookie(&loginCookie) + }, + updateFunc: func(u *models.User) { + u.Password = "" + u.FirstName = "John Updated" + u.LastName = "Doe Updated" + u.Phone = "01738484994" + u.DriversLicence.LicenceNumber = "B072RRE2I50" + var licenceRepo repositories.DriversLicenceInterface = &repositories.DriversLicenceRepository{} + category, err := licenceRepo.FindCategoryByName("A") + assert.NoError(t, err) + u.DriversLicence.LicenceCategories = []models.LicenceCategory{category} + }, + expectedStatus: http.StatusAccepted, + }, { name: "Delete all categories", setupCookie: func(req *http.Request) { @@ -538,7 +577,9 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { u.FirstName = "John Missing ID" }, expectedStatus: http.StatusForbidden, - expectedError: "You are not authorized to update this user", + expectedErrors: []map[string]string{ + {"field": "general", "key": "server.error.unauthorized_update"}, + }, }, { name: "Password Update", @@ -582,7 +623,7 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { t.Fatalf("Failed to marshal user data: %v", err) } - logger.Error.Printf("Updated User: %#v", updatedUser) + // logger.Error.Printf("Updated User: %#v", updatedUser) // Create request req, _ := http.NewRequest("PUT", "/users/"+strconv.FormatUint(uint64(user.ID), 10), bytes.NewBuffer(jsonData)) req.Header.Set("Content-Type", "application/json") @@ -599,18 +640,38 @@ func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { // Perform request router.ServeHTTP(w, req) + bodyBytes, _ := io.ReadAll(w.Body) + t.Logf("Response Body: %s", string(bodyBytes)) // Check status code assert.Equal(t, tt.expectedStatus, w.Code) // Parse response var response map[string]interface{} - err = json.Unmarshal(w.Body.Bytes(), &response) - assert.NoError(t, err) + err = json.Unmarshal(bodyBytes, &response) + if err != nil { + t.Fatalf("Failed to unmarshal response body: %v", err) + } - if tt.expectedError != "" { - assert.Equal(t, tt.expectedError, response["error"]) + if tt.expectedErrors != nil { + errors, ok := response["errors"].([]interface{}) + if !ok { + t.Fatalf("Expected 'errors' field in response, got: %v", response) + } + assert.Len(t, errors, len(tt.expectedErrors), "Unexpected number of errors") + for i, expectedError := range tt.expectedErrors { + if i < len(errors) { + actualError := errors[i].(map[string]interface{}) + assert.Equal(t, expectedError["field"], actualError["field"], "Mismatched error field") + assert.Equal(t, expectedError["key"], actualError["key"], "Mismatched error key") + } + } } else { - assert.Equal(t, "User updated successfully", response["message"]) + // Check for success message + message, ok := response["message"].(string) + if !ok { + t.Fatalf("Expected 'message' field in response, got: %v", response) + } + assert.Equal(t, "User updated successfully", message) // Verify the update in the database updatedUserFromDB, err := Uc.Service.GetUserByID(user.ID) @@ -844,7 +905,7 @@ func getTestUsers() []RegisterUserTest { return []RegisterUserTest{ { Name: "birthday < 18 should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -854,7 +915,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "FirstName empty, should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -864,7 +925,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "LastName Empty should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -874,7 +935,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "EMail wrong format should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "johnexample.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -884,7 +945,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Missing Zip Code should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -894,7 +955,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Missing Address should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -904,7 +965,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Missing City should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -914,7 +975,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Missing IBAN should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -924,7 +985,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Invalid IBAN should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -934,7 +995,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Missing subscription plan should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -944,7 +1005,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Invalid subscription plan should fail", - WantResponse: http.StatusNotFound, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -982,7 +1043,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Subscription constraints not entered; should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.junior.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -993,7 +1054,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "Subscription constraints wrong; should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.junior.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { @@ -1028,7 +1089,7 @@ func getTestUsers() []RegisterUserTest { }, { Name: "wrong driverslicence number, should fail", - WantResponse: http.StatusNotAcceptable, + WantResponse: http.StatusBadRequest, WantDBData: map[string]interface{}{"email": "john.wronglicence.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { diff --git a/internal/middlewares/auth.go b/internal/middlewares/auth.go index 4756554..2f5d651 100644 --- a/internal/middlewares/auth.go +++ b/internal/middlewares/auth.go @@ -78,7 +78,11 @@ func AuthMiddleware() gin.HandlerFunc { tokenString, err := c.Cookie("jwt") if err != nil { logger.Error.Printf("No Auth token: %v\n", err) - c.JSON(http.StatusUnauthorized, gin.H{"error": "No Auth token"}) + c.JSON(http.StatusUnauthorized, + gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.no_auth_token", + }}}) c.Abort() return } @@ -91,7 +95,11 @@ func AuthMiddleware() gin.HandlerFunc { return } logger.Error.Printf("Token(%v) is invalid: %v\n", tokenString, err) - c.JSON(http.StatusUnauthorized, gin.H{"error": "Auth token invalid"}) + c.JSON(http.StatusUnauthorized, + gin.H{"errors": []gin.H{{ + "field": "general", + "key": "server.error.no_auth_token", + }}}) c.Abort() return }