diff --git a/cmd/membership/main.go b/cmd/membership/main.go index 08f2244..64da1ba 100644 --- a/cmd/membership/main.go +++ b/cmd/membership/main.go @@ -17,7 +17,6 @@ func main() { logger.Info.Println("startup...") config.LoadConfig() - logger.Info.Printf("Config loaded: %#v", config.CFG) err := database.Open(config.DB.Path) if err != nil { diff --git a/internal/config/config.go b/internal/config/config.go index ec49fbd..47dc9d5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -103,6 +103,7 @@ func LoadConfig() { BaseURL = CFG.BaseURL Recipients = CFG.Recipients Security = CFG.Security + logger.Info.Printf("Config loaded: %#v", CFG) } // readFile reads the configuration from the specified file path into the provided Config struct. diff --git a/internal/controllers/contactController.go b/internal/controllers/contactController.go index 629925e..8d5508e 100644 --- a/internal/controllers/contactController.go +++ b/internal/controllers/contactController.go @@ -33,18 +33,18 @@ func (cc *ContactController) RelayContactRequest(c *gin.Context) { validate := validator.New() if err := validate.Struct(msgData); err != nil { logger.Error.Printf("Couldn't validate contact form data: %#v: %v", msgData, err) - c.HTML(http.StatusOK, "contactForm_reply.html", gin.H{"Error": "Form submission failed. Please try again."}) + c.HTML(http.StatusNotAcceptable, "contactForm_reply.html", gin.H{"Error": "Form validation failed. Please check again."}) // c.JSON(http.StatusNotAcceptable, gin.H{"error": "Couldn't validate contact form data"}) return } if err := cc.EmailService.RelayContactFormMessage(msgData.Email, msgData.Name, msgData.Message); err != nil { logger.Error.Printf("Couldn't send contact message mail: %v", err) - c.HTML(http.StatusOK, "contactForm_reply.html", gin.H{"Error": "Form submission failed. Please try again."}) + c.HTML(http.StatusInternalServerError, "contactForm_reply.html", gin.H{"Error": "Email submission failed. Please try again."}) // c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't send mail"}) return } // c.JSON(http.StatusAccepted, "Your message has been sent") - c.HTML(http.StatusOK, "contactForm_reply.html", gin.H{"Success": true}) + c.HTML(http.StatusAccepted, "contactForm_reply.html", gin.H{"Success": true}) } diff --git a/internal/controllers/contactController_test.go b/internal/controllers/contactController_test.go index a08b1bd..09605d3 100644 --- a/internal/controllers/contactController_test.go +++ b/internal/controllers/contactController_test.go @@ -34,12 +34,14 @@ func TestContactController(t *testing.T) { } } -func (rt *RelayContactRequestTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder) { +func (rt *RelayContactRequestTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { return GetMockedFormContext(rt.Input, "/contact") } -func (rt *RelayContactRequestTest) RunHandler(c *gin.Context) { - Cc.RelayContactRequest(c) +func (rt *RelayContactRequestTest) RunHandler(c *gin.Context, router *gin.Engine) { + router.POST("/contact", Cc.RelayContactRequest) + router.ServeHTTP(c.Writer, c.Request) + // Cc.RelayContactRequest(c) } func (rt *RelayContactRequestTest) ValidateResponse(w *httptest.ResponseRecorder) error { diff --git a/internal/controllers/controllers_test.go b/internal/controllers/controllers_test.go index 7043011..cc8bac0 100644 --- a/internal/controllers/controllers_test.go +++ b/internal/controllers/controllers_test.go @@ -25,8 +25,8 @@ import ( ) type TestCase interface { - SetupContext() (*gin.Context, *httptest.ResponseRecorder) - RunHandler(*gin.Context) + SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) + RunHandler(*gin.Context, *gin.Engine) ValidateResponse(*httptest.ResponseRecorder) error ValidateResult() error } @@ -125,23 +125,42 @@ func TestSuite(t *testing.T) { } func initSubscriptionPlans() error { - subscription := models.SubscriptionModel{ - Name: "Basic", - Details: "Test Plan", - MonthlyFee: 2, - HourlyRate: 3, + subscriptions := []models.SubscriptionModel{ + { + Name: "Basic", + Details: "Test Plan", + MonthlyFee: 2, + HourlyRate: 3, + }, + { + Name: "additional", + Details: "This plan needs another membership id to validate", + RequiredMembershipField: "ParentMembershipID", + MonthlyFee: 2, + HourlyRate: 3, + }, } - result := database.DB.Create(&subscription) - if result.Error != nil { - return result.Error + for _, subscription := range subscriptions { + + result := database.DB.Create(&subscription) + if result.Error != nil { + return result.Error + } } + return nil } -func GetMockedJSONContext(jsonStr []byte, url string) (*gin.Context, *httptest.ResponseRecorder) { +func GetMockedJSONContext(jsonStr []byte, url string) (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) + + router := gin.New() + + // Load HTML templates + router.LoadHTMLGlob(config.Templates.HTMLPath + "/*") + var err error c.Request, err = http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) if err != nil { @@ -149,22 +168,31 @@ func GetMockedJSONContext(jsonStr []byte, url string) (*gin.Context, *httptest.R } c.Request.Header.Set("Content-Type", "application/json") - return c, w + return c, w, router } -func GetMockedFormContext(formData url.Values, url string) (*gin.Context, *httptest.ResponseRecorder) { +func GetMockedFormContext(formData url.Values, url string) (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) - req, err := http.NewRequest("POST", url, bytes.NewBufferString(formData.Encode())) + router := gin.New() + + // Load HTML templates + router.LoadHTMLGlob(config.Templates.HTMLPath + "/*") + + req, err := http.NewRequest("POST", + url, + bytes.NewBufferString(formData.Encode())) + if err != nil { log.Fatalf("Failed to create new Request: %#v", err) } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") c.Request = req - return c, w + return c, w, router } func deleteTestDB(dbPath string) error { @@ -176,8 +204,8 @@ func deleteTestDB(dbPath string) error { } func runSingleTest(tc TestCase) error { - c, w := tc.SetupContext() - tc.RunHandler(c) + c, w, router := tc.SetupContext() + tc.RunHandler(c, router) if err := tc.ValidateResponse(w); err != nil { return err diff --git a/internal/controllers/membershipController_test.go b/internal/controllers/membershipController_test.go index 8f836ff..b4726d7 100644 --- a/internal/controllers/membershipController_test.go +++ b/internal/controllers/membershipController_test.go @@ -32,11 +32,11 @@ func TestMembershipController(t *testing.T) { } } -func (rt *RegisterSubscriptionTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder) { +func (rt *RegisterSubscriptionTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { return GetMockedJSONContext([]byte(rt.Input), "register/subscription") } -func (rt *RegisterSubscriptionTest) RunHandler(c *gin.Context) { +func (rt *RegisterSubscriptionTest) RunHandler(c *gin.Context, router *gin.Engine) { Mc.RegisterSubscription(c) } diff --git a/internal/controllers/user_controller_test.go b/internal/controllers/user_controller_test.go index 8d7d465..d3116f6 100644 --- a/internal/controllers/user_controller_test.go +++ b/internal/controllers/user_controller_test.go @@ -28,11 +28,11 @@ type RegisterUserTest struct { Assert bool } -func (rt *RegisterUserTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder) { +func (rt *RegisterUserTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { return GetMockedJSONContext([]byte(rt.Input), "register") } -func (rt *RegisterUserTest) RunHandler(c *gin.Context) { +func (rt *RegisterUserTest) RunHandler(c *gin.Context, router *gin.Engine) { Uc.RegisterUser(c) } @@ -215,7 +215,7 @@ func checkVerificationMail(message *utils.Email, user *models.User) error { func verifyMail(verificationURL string) error { gin.SetMode(gin.TestMode) router := gin.New() - router.LoadHTMLGlob(filepath.Join(config.Templates.HTMLPath, "*")) // Adjust the path to your HTML templates + router.LoadHTMLGlob(filepath.Join(config.Templates.HTMLPath, "*")) router.GET("/backend/verify", Uc.VerifyMailHandler) wv := httptest.NewRecorder() @@ -413,5 +413,40 @@ func getTestUsers() []RegisterUserTest { return user })), }, + { + Name: "Subscription constraints not entered; should fail", + WantResponse: http.StatusNotAcceptable, + WantDBData: map[string]interface{}{"Email": "john.junior.doe@example.com"}, + Assert: false, + Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { + user.Email = "john.junior.doe@example.com" + user.Membership.SubscriptionModel.Name = "additional" + return user + })), + }, + { + Name: "Subscription constraints wrong; should fail", + WantResponse: http.StatusNotAcceptable, + WantDBData: map[string]interface{}{"Email": "john.junior.doe@example.com"}, + Assert: false, + Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { + user.Email = "john.junior.doe@example.com" + user.Membership.ParentMembershipID = 200 + user.Membership.SubscriptionModel.Name = "additional" + return user + })), + }, + { + Name: "Subscription constraints correct, should pass", + WantResponse: http.StatusCreated, + WantDBData: map[string]interface{}{"Email": "john.junior.doe@example.com"}, + Assert: true, + Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { + user.Email = "john.junior.doe@example.com" + user.Membership.ParentMembershipID = 1 + user.Membership.SubscriptionModel.Name = "additional" + return user + })), + }, } } diff --git a/internal/middlewares/cors.go b/internal/middlewares/cors.go index 285a10c..b3470b1 100644 --- a/internal/middlewares/cors.go +++ b/internal/middlewares/cors.go @@ -11,8 +11,8 @@ import ( func CORSMiddleware() gin.HandlerFunc { logger.Info.Print("Applying CORS") return cors.New(cors.Config{ - AllowOrigins: []string{config.BaseURL}, // Add your frontend URL(s) - AllowMethods: []string{"GET", "POST"}, // "PUT", "PATCH", "DELETE", "OPTIONS"}, + AllowOrigins: []string{config.BaseURL, "http://localhost:8080"}, // Add your frontend URL(s) + AllowMethods: []string{"GET", "POST"}, // "PUT", "PATCH", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With"}, // ExposeHeaders: []string{"Content-Length"}, AllowCredentials: true,