From d785464186523e9c05c7c5c56d67e6d5f49d7887 Mon Sep 17 00:00:00 2001 From: helmytrisna86 Date: Tue, 27 May 2025 07:56:41 +0000 Subject: [PATCH] refactor(depedencies injection): refactoring depedencies injection to automatic injection --- go.mod | 1 + go.sum | 2 + src/controller/auth_controller.go | 48 ++++++------ src/controller/health_check_controller.go | 34 ++++----- src/controller/user_controller.go | 22 +++--- src/middleware/auth.go | 2 +- src/router/auth_route.go | 10 +-- src/router/health_check_route.go | 4 +- src/router/router.go | 42 +++++++---- src/router/user_route.go | 16 ++-- src/service/auth_service.go | 91 ++++++++++------------- src/service/email_service.go | 30 +++----- src/service/health_check_service.go | 33 ++++---- src/service/token_service.go | 35 +++------ src/service/user_service.go | 33 +++----- 15 files changed, 188 insertions(+), 215 deletions(-) diff --git a/go.mod b/go.mod index 7bd3528..83f861f 100644 --- a/go.mod +++ b/go.mod @@ -73,6 +73,7 @@ require ( github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect go.uber.org/atomic v1.9.0 // indirect + go.uber.org/dig v1.19.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect diff --git a/go.sum b/go.sum index 0a1a609..0e90a0b 100644 --- a/go.sum +++ b/go.sum @@ -152,6 +152,8 @@ github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7Fw github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= +go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= diff --git a/src/controller/auth_controller.go b/src/controller/auth_controller.go index 413742e..e3d4d4a 100644 --- a/src/controller/auth_controller.go +++ b/src/controller/auth_controller.go @@ -16,21 +16,21 @@ import ( ) type AuthController struct { - AuthService service.AuthService - UserService service.UserService - TokenService service.TokenService - EmailService service.EmailService + authService *service.AuthService + userService *service.UserService + tokenService *service.TokenService + emailService *service.EmailService } func NewAuthController( - authService service.AuthService, userService service.UserService, - tokenService service.TokenService, emailService service.EmailService, + authService *service.AuthService, userService *service.UserService, + tokenService *service.TokenService, emailService *service.EmailService, ) *AuthController { return &AuthController{ - AuthService: authService, - UserService: userService, - TokenService: tokenService, - EmailService: emailService, + authService, + userService, + tokenService, + emailService, } } @@ -49,12 +49,12 @@ func (a *AuthController) Register(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - user, err := a.AuthService.Register(c, req) + user, err := a.authService.Register(c, req) if err != nil { return err } - tokens, err := a.TokenService.GenerateAuthTokens(c, user) + tokens, err := a.tokenService.GenerateAuthTokens(c, user) if err != nil { return err } @@ -84,12 +84,12 @@ func (a *AuthController) Login(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - user, err := a.AuthService.Login(c, req) + user, err := a.authService.Login(c, req) if err != nil { return err } - tokens, err := a.TokenService.GenerateAuthTokens(c, user) + tokens, err := a.tokenService.GenerateAuthTokens(c, user) if err != nil { return err } @@ -119,7 +119,7 @@ func (a *AuthController) Logout(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - if err := a.AuthService.Logout(c, req); err != nil { + if err := a.authService.Logout(c, req); err != nil { return err } @@ -146,7 +146,7 @@ func (a *AuthController) RefreshTokens(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - tokens, err := a.AuthService.RefreshAuth(c, req) + tokens, err := a.authService.RefreshAuth(c, req) if err != nil { return err } @@ -175,12 +175,12 @@ func (a *AuthController) ForgotPassword(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - resetPasswordToken, err := a.TokenService.GenerateResetPasswordToken(c, req) + resetPasswordToken, err := a.tokenService.GenerateResetPasswordToken(c, req) if err != nil { return err } - if errEmail := a.EmailService.SendResetPasswordEmail(req.Email, resetPasswordToken); errEmail != nil { + if errEmail := a.emailService.SendResetPasswordEmail(req.Email, resetPasswordToken); errEmail != nil { return errEmail } @@ -211,7 +211,7 @@ func (a *AuthController) ResetPassword(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - if err := a.AuthService.ResetPassword(c, query, req); err != nil { + if err := a.authService.ResetPassword(c, query, req); err != nil { return err } @@ -234,12 +234,12 @@ func (a *AuthController) ResetPassword(c *fiber.Ctx) error { func (a *AuthController) SendVerificationEmail(c *fiber.Ctx) error { user, _ := c.Locals("user").(*model.User) - verifyEmailToken, err := a.TokenService.GenerateVerifyEmailToken(c, user) + verifyEmailToken, err := a.tokenService.GenerateVerifyEmailToken(c, user) if err != nil { return err } - if errEmail := a.EmailService.SendVerificationEmail(user.Email, *verifyEmailToken); errEmail != nil { + if errEmail := a.emailService.SendVerificationEmail(user.Email, *verifyEmailToken); errEmail != nil { return errEmail } @@ -263,7 +263,7 @@ func (a *AuthController) VerifyEmail(c *fiber.Ctx) error { Token: c.Query("token"), } - if err := a.AuthService.VerifyEmail(c, query); err != nil { + if err := a.authService.VerifyEmail(c, query); err != nil { return err } @@ -336,12 +336,12 @@ func (a *AuthController) GoogleCallback(c *fiber.Ctx) error { return errJSON } - user, err := a.UserService.CreateGoogleUser(c, googleUser) + user, err := a.userService.CreateGoogleUser(c, googleUser) if err != nil { return err } - tokens, err := a.TokenService.GenerateAuthTokens(c, user) + tokens, err := a.tokenService.GenerateAuthTokens(c, user) if err != nil { return err } diff --git a/src/controller/health_check_controller.go b/src/controller/health_check_controller.go index 94fac0a..2f60927 100644 --- a/src/controller/health_check_controller.go +++ b/src/controller/health_check_controller.go @@ -8,12 +8,12 @@ import ( ) type HealthCheckController struct { - HealthCheckService service.HealthCheckService + healthCheckService *service.HealthCheckService } -func NewHealthCheckController(healthCheckService service.HealthCheckService) *HealthCheckController { +func NewHealthCheckController(healthCheckService *service.HealthCheckService) *HealthCheckController { return &HealthCheckController{ - HealthCheckService: healthCheckService, + healthCheckService, } } @@ -46,27 +46,23 @@ func (h *HealthCheckController) Check(c *fiber.Ctx) error { isHealthy := true var serviceList []response.HealthCheck - // Check the database connection - if err := h.HealthCheckService.GormCheck(); err != nil { - isHealthy = false - errMsg := err.Error() - h.addServiceStatus(&serviceList, "Postgre", false, &errMsg) - } else { - h.addServiceStatus(&serviceList, "Postgre", true, nil) + // Helper to run a health check, update status and add to list + checkStatus := func(name string, fn func() error) { + err := fn() + if err != nil { + isHealthy = false + errMsg := err.Error() + h.addServiceStatus(&serviceList, name, false, &errMsg) + } else { + h.addServiceStatus(&serviceList, name, true, nil) + } } - if err := h.HealthCheckService.MemoryHeapCheck(); err != nil { - isHealthy = false - errMsg := err.Error() - h.addServiceStatus(&serviceList, "Memory", false, &errMsg) - } else { - h.addServiceStatus(&serviceList, "Memory", true, nil) - } + checkStatus("Postgre", h.healthCheckService.GormCheck) + checkStatus("Memory", h.healthCheckService.MemoryHeapCheck) - // Return the response based on health check result statusCode := fiber.StatusOK status := "success" - if !isHealthy { statusCode = fiber.StatusInternalServerError status = "error" diff --git a/src/controller/user_controller.go b/src/controller/user_controller.go index 780aeb3..25a1b35 100644 --- a/src/controller/user_controller.go +++ b/src/controller/user_controller.go @@ -12,14 +12,14 @@ import ( ) type UserController struct { - UserService service.UserService - TokenService service.TokenService + userService *service.UserService + tokenService *service.TokenService } -func NewUserController(userService service.UserService, tokenService service.TokenService) *UserController { +func NewUserController(userService *service.UserService, tokenService *service.TokenService) *UserController { return &UserController{ - UserService: userService, - TokenService: tokenService, + userService, + tokenService, } } @@ -42,7 +42,7 @@ func (u *UserController) GetUsers(c *fiber.Ctx) error { Search: c.Query("search", ""), } - users, totalResults, err := u.UserService.GetUsers(c, query) + users, totalResults, err := u.userService.GetUsers(c, query) if err != nil { return err } @@ -78,7 +78,7 @@ func (u *UserController) GetUserByID(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") } - user, err := u.UserService.GetUserByID(c, userID) + user, err := u.userService.GetUserByID(c, userID) if err != nil { return err } @@ -110,7 +110,7 @@ func (u *UserController) CreateUser(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - user, err := u.UserService.CreateUser(c, req) + user, err := u.userService.CreateUser(c, req) if err != nil { return err } @@ -149,7 +149,7 @@ func (u *UserController) UpdateUser(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - user, err := u.UserService.UpdateUser(c, req, userID) + user, err := u.userService.UpdateUser(c, req, userID) if err != nil { return err } @@ -181,11 +181,11 @@ func (u *UserController) DeleteUser(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") } - if err := u.TokenService.DeleteAllToken(c, userID); err != nil { + if err := u.tokenService.DeleteAllToken(c, userID); err != nil { return err } - if err := u.UserService.DeleteUser(c, userID); err != nil { + if err := u.userService.DeleteUser(c, userID); err != nil { return err } diff --git a/src/middleware/auth.go b/src/middleware/auth.go index 1b0d1a3..901db57 100644 --- a/src/middleware/auth.go +++ b/src/middleware/auth.go @@ -9,7 +9,7 @@ import ( "github.com/gofiber/fiber/v2" ) -func Auth(userService service.UserService, requiredRights ...string) fiber.Handler { +func Auth(userService *service.UserService, requiredRights ...string) fiber.Handler { return func(c *fiber.Ctx) error { authHeader := c.Get("Authorization") token := strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer ")) diff --git a/src/router/auth_route.go b/src/router/auth_route.go index 37b358f..6cd4ac2 100644 --- a/src/router/auth_route.go +++ b/src/router/auth_route.go @@ -3,17 +3,17 @@ package router import ( "app/src/config" "app/src/controller" - m "app/src/middleware" + "app/src/middleware" "app/src/service" "github.com/gofiber/fiber/v2" ) func AuthRoutes( - v1 fiber.Router, a service.AuthService, u service.UserService, - t service.TokenService, e service.EmailService, + v1 fiber.Router, authService *service.AuthService, userService *service.UserService, + tokenService *service.TokenService, emailService *service.EmailService, ) { - authController := controller.NewAuthController(a, u, t, e) + authController := controller.NewAuthController(authService, userService, tokenService, emailService) config.GoogleConfig() auth := v1.Group("/auth") @@ -24,7 +24,7 @@ func AuthRoutes( auth.Post("/refresh-tokens", authController.RefreshTokens) auth.Post("/forgot-password", authController.ForgotPassword) auth.Post("/reset-password", authController.ResetPassword) - auth.Post("/send-verification-email", m.Auth(u), authController.SendVerificationEmail) + auth.Post("/send-verification-email", middleware.Auth(userService), authController.SendVerificationEmail) auth.Post("/verify-email", authController.VerifyEmail) auth.Get("/google", authController.GoogleLogin) auth.Get("/google-callback", authController.GoogleCallback) diff --git a/src/router/health_check_route.go b/src/router/health_check_route.go index a6ef6fd..271c125 100644 --- a/src/router/health_check_route.go +++ b/src/router/health_check_route.go @@ -7,8 +7,8 @@ import ( "github.com/gofiber/fiber/v2" ) -func HealthCheckRoutes(v1 fiber.Router, h service.HealthCheckService) { - healthCheckController := controller.NewHealthCheckController(h) +func HealthCheckRoutes(v1 fiber.Router, healthCheckService *service.HealthCheckService) { + healthCheckController := controller.NewHealthCheckController(healthCheckService) healthCheck := v1.Group("/health-check") healthCheck.Get("/", healthCheckController.Check) diff --git a/src/router/router.go b/src/router/router.go index 32d8753..87f2f40 100644 --- a/src/router/router.go +++ b/src/router/router.go @@ -6,26 +6,42 @@ import ( "app/src/validation" "github.com/gofiber/fiber/v2" + "go.uber.org/dig" "gorm.io/gorm" ) func Routes(app *fiber.App, db *gorm.DB) { - validate := validation.Validator() + container := dig.New() - healthCheckService := service.NewHealthCheckService(db) - emailService := service.NewEmailService() - userService := service.NewUserService(db, validate) - tokenService := service.NewTokenService(db, validate, userService) - authService := service.NewAuthService(db, validate, userService, tokenService) + container.Provide(func() *gorm.DB { return db }) + container.Provide(validation.Validator) - v1 := app.Group("/v1") + container.Provide(service.NewHealthCheckService) + container.Provide(service.NewEmailService) + container.Provide(service.NewUserService) + container.Provide(service.NewTokenService) + container.Provide(service.NewAuthService) - HealthCheckRoutes(v1, healthCheckService) - AuthRoutes(v1, authService, userService, tokenService, emailService) - UserRoutes(v1, userService, tokenService) - // TODO: add another routes here... + // Invoke route setup with auto-injected dependencies + err := container.Invoke(func( + healthCheckService *service.HealthCheckService, + emailService *service.EmailService, + userService *service.UserService, + tokenService *service.TokenService, + authService *service.AuthService, + ) { + v1 := app.Group("/v1") - if !config.IsProd { - DocsRoutes(v1) + HealthCheckRoutes(v1, healthCheckService) + AuthRoutes(v1, authService, userService, tokenService, emailService) + UserRoutes(v1, userService, tokenService) + + if !config.IsProd { + DocsRoutes(v1) + } + }) + + if err != nil { + panic(err) } } diff --git a/src/router/user_route.go b/src/router/user_route.go index e3c3f12..1f5ba94 100644 --- a/src/router/user_route.go +++ b/src/router/user_route.go @@ -2,20 +2,20 @@ package router import ( "app/src/controller" - m "app/src/middleware" + "app/src/middleware" "app/src/service" "github.com/gofiber/fiber/v2" ) -func UserRoutes(v1 fiber.Router, u service.UserService, t service.TokenService) { - userController := controller.NewUserController(u, t) +func UserRoutes(v1 fiber.Router, userService *service.UserService, tokenService *service.TokenService) { + userController := controller.NewUserController(userService, tokenService) user := v1.Group("/users") - user.Get("/", m.Auth(u, "getUsers"), userController.GetUsers) - user.Post("/", m.Auth(u, "manageUsers"), userController.CreateUser) - user.Get("/:userId", m.Auth(u, "getUsers"), userController.GetUserByID) - user.Patch("/:userId", m.Auth(u, "manageUsers"), userController.UpdateUser) - user.Delete("/:userId", m.Auth(u, "manageUsers"), userController.DeleteUser) + user.Get("/", middleware.Auth(userService, "getUsers"), userController.GetUsers) + user.Post("/", middleware.Auth(userService, "manageUsers"), userController.CreateUser) + user.Get("/:userId", middleware.Auth(userService, "getUsers"), userController.GetUserByID) + user.Patch("/:userId", middleware.Auth(userService, "manageUsers"), userController.UpdateUser) + user.Delete("/:userId", middleware.Auth(userService, "manageUsers"), userController.DeleteUser) } diff --git a/src/service/auth_service.go b/src/service/auth_service.go index 60dd07c..7c320e0 100644 --- a/src/service/auth_service.go +++ b/src/service/auth_service.go @@ -14,43 +14,34 @@ import ( "gorm.io/gorm" ) -type AuthService interface { - Register(c *fiber.Ctx, req *validation.Register) (*model.User, error) - Login(c *fiber.Ctx, req *validation.Login) (*model.User, error) - Logout(c *fiber.Ctx, req *validation.Logout) error - RefreshAuth(c *fiber.Ctx, req *validation.RefreshToken) (*response.Tokens, error) - ResetPassword(c *fiber.Ctx, query *validation.Token, req *validation.UpdatePassOrVerify) error - VerifyEmail(c *fiber.Ctx, query *validation.Token) error -} - -type authService struct { - Log *logrus.Logger - DB *gorm.DB - Validate *validator.Validate - UserService UserService - TokenService TokenService +type AuthService struct { + log *logrus.Logger + db *gorm.DB + validate *validator.Validate + userService *UserService + tokenService *TokenService } func NewAuthService( - db *gorm.DB, validate *validator.Validate, userService UserService, tokenService TokenService, -) AuthService { - return &authService{ - Log: utils.Log, - DB: db, - Validate: validate, - UserService: userService, - TokenService: tokenService, + db *gorm.DB, validate *validator.Validate, userService *UserService, tokenService *TokenService, +) *AuthService { + return &AuthService{ + log: utils.Log, + db: db, + validate: validate, + userService: userService, + tokenService: tokenService, } } -func (s *authService) Register(c *fiber.Ctx, req *validation.Register) (*model.User, error) { - if err := s.Validate.Struct(req); err != nil { +func (s *AuthService) Register(c *fiber.Ctx, req *validation.Register) (*model.User, error) { + if err := s.validate.Struct(req); err != nil { return nil, err } hashedPassword, err := utils.HashPassword(req.Password) if err != nil { - s.Log.Errorf("Failed hash password: %+v", err) + s.log.Errorf("Failed hash password: %+v", err) return nil, err } @@ -60,24 +51,24 @@ func (s *authService) Register(c *fiber.Ctx, req *validation.Register) (*model.U Password: hashedPassword, } - result := s.DB.WithContext(c.Context()).Create(user) + result := s.db.WithContext(c.Context()).Create(user) if errors.Is(result.Error, gorm.ErrDuplicatedKey) { return nil, fiber.NewError(fiber.StatusConflict, "Email already taken") } if result.Error != nil { - s.Log.Errorf("Failed create user: %+v", result.Error) + s.log.Errorf("Failed create user: %+v", result.Error) } return user, result.Error } -func (s *authService) Login(c *fiber.Ctx, req *validation.Login) (*model.User, error) { - if err := s.Validate.Struct(req); err != nil { +func (s *AuthService) Login(c *fiber.Ctx, req *validation.Login) (*model.User, error) { + if err := s.validate.Struct(req); err != nil { return nil, err } - user, err := s.UserService.GetUserByEmail(c, req.Email) + user, err := s.userService.GetUserByEmail(c, req.Email) if err != nil { return nil, fiber.NewError(fiber.StatusUnauthorized, "Invalid email or password") } @@ -89,37 +80,37 @@ func (s *authService) Login(c *fiber.Ctx, req *validation.Login) (*model.User, e return user, nil } -func (s *authService) Logout(c *fiber.Ctx, req *validation.Logout) error { - if err := s.Validate.Struct(req); err != nil { +func (s *AuthService) Logout(c *fiber.Ctx, req *validation.Logout) error { + if err := s.validate.Struct(req); err != nil { return err } - token, err := s.TokenService.GetTokenByUserID(c, req.RefreshToken) + token, err := s.tokenService.GetTokenByUserID(c, req.RefreshToken) if err != nil { return fiber.NewError(fiber.StatusNotFound, "Token not found") } - err = s.TokenService.DeleteToken(c, config.TokenTypeRefresh, token.UserID.String()) + err = s.tokenService.DeleteToken(c, config.TokenTypeRefresh, token.UserID.String()) return err } -func (s *authService) RefreshAuth(c *fiber.Ctx, req *validation.RefreshToken) (*response.Tokens, error) { - if err := s.Validate.Struct(req); err != nil { +func (s *AuthService) RefreshAuth(c *fiber.Ctx, req *validation.RefreshToken) (*response.Tokens, error) { + if err := s.validate.Struct(req); err != nil { return nil, err } - token, err := s.TokenService.GetTokenByUserID(c, req.RefreshToken) + token, err := s.tokenService.GetTokenByUserID(c, req.RefreshToken) if err != nil { return nil, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate") } - user, err := s.UserService.GetUserByID(c, token.UserID.String()) + user, err := s.userService.GetUserByID(c, token.UserID.String()) if err != nil { return nil, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate") } - newTokens, err := s.TokenService.GenerateAuthTokens(c, user) + newTokens, err := s.tokenService.GenerateAuthTokens(c, user) if err != nil { return nil, fiber.ErrInternalServerError } @@ -127,8 +118,8 @@ func (s *authService) RefreshAuth(c *fiber.Ctx, req *validation.RefreshToken) (* return newTokens, err } -func (s *authService) ResetPassword(c *fiber.Ctx, query *validation.Token, req *validation.UpdatePassOrVerify) error { - if err := s.Validate.Struct(query); err != nil { +func (s *AuthService) ResetPassword(c *fiber.Ctx, query *validation.Token, req *validation.UpdatePassOrVerify) error { + if err := s.validate.Struct(query); err != nil { return err } @@ -137,24 +128,24 @@ func (s *authService) ResetPassword(c *fiber.Ctx, query *validation.Token, req * return fiber.NewError(fiber.StatusUnauthorized, "Invalid Token") } - user, err := s.UserService.GetUserByID(c, userID) + user, err := s.userService.GetUserByID(c, userID) if err != nil { return fiber.NewError(fiber.StatusUnauthorized, "Password reset failed") } - if errUpdate := s.UserService.UpdatePassOrVerify(c, req, user.ID.String()); errUpdate != nil { + if errUpdate := s.userService.UpdatePassOrVerify(c, req, user.ID.String()); errUpdate != nil { return errUpdate } - if errToken := s.TokenService.DeleteToken(c, config.TokenTypeResetPassword, user.ID.String()); errToken != nil { + if errToken := s.tokenService.DeleteToken(c, config.TokenTypeResetPassword, user.ID.String()); errToken != nil { return errToken } return nil } -func (s *authService) VerifyEmail(c *fiber.Ctx, query *validation.Token) error { - if err := s.Validate.Struct(query); err != nil { +func (s *AuthService) VerifyEmail(c *fiber.Ctx, query *validation.Token) error { + if err := s.validate.Struct(query); err != nil { return err } @@ -163,12 +154,12 @@ func (s *authService) VerifyEmail(c *fiber.Ctx, query *validation.Token) error { return fiber.NewError(fiber.StatusUnauthorized, "Invalid Token") } - user, err := s.UserService.GetUserByID(c, userID) + user, err := s.userService.GetUserByID(c, userID) if err != nil { return fiber.NewError(fiber.StatusUnauthorized, "Verify email failed") } - if errToken := s.TokenService.DeleteToken(c, config.TokenTypeVerifyEmail, user.ID.String()); errToken != nil { + if errToken := s.tokenService.DeleteToken(c, config.TokenTypeVerifyEmail, user.ID.String()); errToken != nil { return errToken } @@ -176,7 +167,7 @@ func (s *authService) VerifyEmail(c *fiber.Ctx, query *validation.Token) error { VerifiedEmail: true, } - if errUpdate := s.UserService.UpdatePassOrVerify(c, updateBody, user.ID.String()); errUpdate != nil { + if errUpdate := s.userService.UpdatePassOrVerify(c, updateBody, user.ID.String()); errUpdate != nil { return errUpdate } diff --git a/src/service/email_service.go b/src/service/email_service.go index 544c4d9..43d1893 100644 --- a/src/service/email_service.go +++ b/src/service/email_service.go @@ -9,21 +9,15 @@ import ( "gopkg.in/gomail.v2" ) -type EmailService interface { - SendEmail(to, subject, body string) error - SendResetPasswordEmail(to, token string) error - SendVerificationEmail(to, token string) error +type EmailService struct { + log *logrus.Logger + dialer *gomail.Dialer } -type emailService struct { - Log *logrus.Logger - Dialer *gomail.Dialer -} - -func NewEmailService() EmailService { - return &emailService{ - Log: utils.Log, - Dialer: gomail.NewDialer( +func NewEmailService() *EmailService { + return &EmailService{ + log: utils.Log, + dialer: gomail.NewDialer( config.SMTPHost, config.SMTPPort, config.SMTPUsername, @@ -32,22 +26,22 @@ func NewEmailService() EmailService { } } -func (s *emailService) SendEmail(to, subject, body string) error { +func (s *EmailService) SendEmail(to, subject, body string) error { mailer := gomail.NewMessage() mailer.SetHeader("From", config.EmailFrom) mailer.SetHeader("To", to) mailer.SetHeader("Subject", subject) mailer.SetBody("text/plain", body) - if err := s.Dialer.DialAndSend(mailer); err != nil { - s.Log.Errorf("Failed to send email: %v", err) + if err := s.dialer.DialAndSend(mailer); err != nil { + s.log.Errorf("Failed to send email: %v", err) return err } return nil } -func (s *emailService) SendResetPasswordEmail(to, token string) error { +func (s *EmailService) SendResetPasswordEmail(to, token string) error { subject := "Reset password" // TODO: replace this url with the link to the reset password page of your front-end app @@ -60,7 +54,7 @@ If you did not request any password resets, then ignore this email.`, resetPassw return s.SendEmail(to, subject, body) } -func (s *emailService) SendVerificationEmail(to, token string) error { +func (s *EmailService) SendVerificationEmail(to, token string) error { subject := "Email Verification" // TODO: replace this url with the link to the email verification page of your front-end app diff --git a/src/service/health_check_service.go b/src/service/health_check_service.go index 916ece9..d3690b2 100644 --- a/src/service/health_check_service.go +++ b/src/service/health_check_service.go @@ -9,32 +9,27 @@ import ( "gorm.io/gorm" ) -type HealthCheckService interface { - GormCheck() error - MemoryHeapCheck() error +type HealthCheckService struct { + log *logrus.Logger + db *gorm.DB } -type healthCheckService struct { - Log *logrus.Logger - DB *gorm.DB -} - -func NewHealthCheckService(db *gorm.DB) HealthCheckService { - return &healthCheckService{ - Log: utils.Log, - DB: db, +func NewHealthCheckService(db *gorm.DB) *HealthCheckService { + return &HealthCheckService{ + log: utils.Log, + db: db, } } -func (s *healthCheckService) GormCheck() error { - sqlDB, errDB := s.DB.DB() +func (s *HealthCheckService) GormCheck() error { + sqlDB, errDB := s.db.DB() if errDB != nil { - s.Log.Errorf("failed to access the database connection pool: %v", errDB) + s.log.Errorf("failed to access the database connection pool: %v", errDB) return errDB } if err := sqlDB.Ping(); err != nil { - s.Log.Errorf("failed to ping the database: %v", err) + s.log.Errorf("failed to ping the database: %v", err) return err } @@ -42,18 +37,18 @@ func (s *healthCheckService) GormCheck() error { } // MemoryHeapCheck checks if heap memory usage exceeds a threshold -func (s *healthCheckService) MemoryHeapCheck() error { +func (s *HealthCheckService) MemoryHeapCheck() error { var memStats runtime.MemStats runtime.ReadMemStats(&memStats) // Collect memory statistics heapAlloc := memStats.HeapAlloc // Heap memory currently allocated heapThreshold := uint64(300 * 1024 * 1024) // Example threshold: 300 MB - s.Log.Infof("Heap Memory Allocation: %v bytes", heapAlloc) + s.log.Infof("Heap Memory Allocation: %v bytes", heapAlloc) // If the heap allocation exceeds the threshold, return an error if heapAlloc > heapThreshold { - s.Log.Errorf("Heap memory usage exceeds threshold: %v bytes", heapAlloc) + s.log.Errorf("Heap memory usage exceeds threshold: %v bytes", heapAlloc) return errors.New("heap memory usage too high") } diff --git a/src/service/token_service.go b/src/service/token_service.go index cdc1f8e..3d73fb8 100644 --- a/src/service/token_service.go +++ b/src/service/token_service.go @@ -16,26 +16,15 @@ import ( "gorm.io/gorm" ) -type TokenService interface { - GenerateToken(userID string, expires time.Time, tokenType string) (string, error) - SaveToken(c *fiber.Ctx, token, userID, tokenType string, expires time.Time) error - DeleteToken(c *fiber.Ctx, tokenType string, userID string) error - DeleteAllToken(c *fiber.Ctx, userID string) error - GetTokenByUserID(c *fiber.Ctx, tokenStr string) (*model.Token, error) - GenerateAuthTokens(c *fiber.Ctx, user *model.User) (*res.Tokens, error) - GenerateResetPasswordToken(c *fiber.Ctx, req *validation.ForgotPassword) (string, error) - GenerateVerifyEmailToken(c *fiber.Ctx, user *model.User) (*string, error) -} - -type tokenService struct { +type TokenService struct { Log *logrus.Logger DB *gorm.DB Validate *validator.Validate - UserService UserService + UserService *UserService } -func NewTokenService(db *gorm.DB, validate *validator.Validate, userService UserService) TokenService { - return &tokenService{ +func NewTokenService(db *gorm.DB, validate *validator.Validate, userService *UserService) *TokenService { + return &TokenService{ Log: utils.Log, DB: db, Validate: validate, @@ -43,7 +32,7 @@ func NewTokenService(db *gorm.DB, validate *validator.Validate, userService User } } -func (s *tokenService) GenerateToken(userID string, expires time.Time, tokenType string) (string, error) { +func (s *TokenService) GenerateToken(userID string, expires time.Time, tokenType string) (string, error) { claims := jwt.MapClaims{ "sub": userID, "iat": time.Now().Unix(), @@ -55,7 +44,7 @@ func (s *tokenService) GenerateToken(userID string, expires time.Time, tokenType return token.SignedString([]byte(config.JWTSecret)) } -func (s *tokenService) SaveToken(c *fiber.Ctx, token, userID, tokenType string, expires time.Time) error { +func (s *TokenService) SaveToken(c *fiber.Ctx, token, userID, tokenType string, expires time.Time) error { if err := s.DeleteToken(c, tokenType, userID); err != nil { return err } @@ -76,7 +65,7 @@ func (s *tokenService) SaveToken(c *fiber.Ctx, token, userID, tokenType string, return result.Error } -func (s *tokenService) DeleteToken(c *fiber.Ctx, tokenType string, userID string) error { +func (s *TokenService) DeleteToken(c *fiber.Ctx, tokenType string, userID string) error { tokenDoc := new(model.Token) result := s.DB.WithContext(c.Context()). @@ -90,7 +79,7 @@ func (s *tokenService) DeleteToken(c *fiber.Ctx, tokenType string, userID string return result.Error } -func (s *tokenService) DeleteAllToken(c *fiber.Ctx, userID string) error { +func (s *TokenService) DeleteAllToken(c *fiber.Ctx, userID string) error { tokenDoc := new(model.Token) result := s.DB.WithContext(c.Context()).Where("user_id = ?", userID).Delete(tokenDoc) @@ -102,7 +91,7 @@ func (s *tokenService) DeleteAllToken(c *fiber.Ctx, userID string) error { return result.Error } -func (s *tokenService) GetTokenByUserID(c *fiber.Ctx, tokenStr string) (*model.Token, error) { +func (s *TokenService) GetTokenByUserID(c *fiber.Ctx, tokenStr string) (*model.Token, error) { userID, err := utils.VerifyToken(tokenStr, config.JWTSecret, config.TokenTypeRefresh) if err != nil { return nil, err @@ -122,7 +111,7 @@ func (s *tokenService) GetTokenByUserID(c *fiber.Ctx, tokenStr string) (*model.T return tokenDoc, nil } -func (s *tokenService) GenerateAuthTokens(c *fiber.Ctx, user *model.User) (*res.Tokens, error) { +func (s *TokenService) GenerateAuthTokens(c *fiber.Ctx, user *model.User) (*res.Tokens, error) { accessTokenExpires := time.Now().UTC().Add(time.Minute * time.Duration(config.JWTAccessExp)) accessToken, err := s.GenerateToken(user.ID.String(), accessTokenExpires, config.TokenTypeAccess) if err != nil { @@ -153,7 +142,7 @@ func (s *tokenService) GenerateAuthTokens(c *fiber.Ctx, user *model.User) (*res. }, nil } -func (s *tokenService) GenerateResetPasswordToken(c *fiber.Ctx, req *validation.ForgotPassword) (string, error) { +func (s *TokenService) GenerateResetPasswordToken(c *fiber.Ctx, req *validation.ForgotPassword) (string, error) { if err := s.Validate.Struct(req); err != nil { return "", err } @@ -177,7 +166,7 @@ func (s *tokenService) GenerateResetPasswordToken(c *fiber.Ctx, req *validation. return resetPasswordToken, nil } -func (s *tokenService) GenerateVerifyEmailToken(c *fiber.Ctx, user *model.User) (*string, error) { +func (s *TokenService) GenerateVerifyEmailToken(c *fiber.Ctx, user *model.User) (*string, error) { expires := time.Now().UTC().Add(time.Minute * time.Duration(config.JWTVerifyEmailExp)) verifyEmailToken, err := s.GenerateToken(user.ID.String(), expires, config.TokenTypeVerifyEmail) if err != nil { diff --git a/src/service/user_service.go b/src/service/user_service.go index c818d72..f5271dd 100644 --- a/src/service/user_service.go +++ b/src/service/user_service.go @@ -12,32 +12,21 @@ import ( "gorm.io/gorm" ) -type UserService interface { - GetUsers(c *fiber.Ctx, params *validation.QueryUser) ([]model.User, int64, error) - GetUserByID(c *fiber.Ctx, id string) (*model.User, error) - GetUserByEmail(c *fiber.Ctx, email string) (*model.User, error) - CreateUser(c *fiber.Ctx, req *validation.CreateUser) (*model.User, error) - UpdatePassOrVerify(c *fiber.Ctx, req *validation.UpdatePassOrVerify, id string) error - UpdateUser(c *fiber.Ctx, req *validation.UpdateUser, id string) (*model.User, error) - DeleteUser(c *fiber.Ctx, id string) error - CreateGoogleUser(c *fiber.Ctx, req *validation.GoogleLogin) (*model.User, error) -} - -type userService struct { +type UserService struct { Log *logrus.Logger DB *gorm.DB Validate *validator.Validate } -func NewUserService(db *gorm.DB, validate *validator.Validate) UserService { - return &userService{ +func NewUserService(db *gorm.DB, validate *validator.Validate) *UserService { + return &UserService{ Log: utils.Log, DB: db, Validate: validate, } } -func (s *userService) GetUsers(c *fiber.Ctx, params *validation.QueryUser) ([]model.User, int64, error) { +func (s *UserService) GetUsers(c *fiber.Ctx, params *validation.QueryUser) ([]model.User, int64, error) { var users []model.User var totalResults int64 @@ -68,7 +57,7 @@ func (s *userService) GetUsers(c *fiber.Ctx, params *validation.QueryUser) ([]mo return users, totalResults, result.Error } -func (s *userService) GetUserByID(c *fiber.Ctx, id string) (*model.User, error) { +func (s *UserService) GetUserByID(c *fiber.Ctx, id string) (*model.User, error) { user := new(model.User) result := s.DB.WithContext(c.Context()).First(user, "id = ?", id) @@ -84,7 +73,7 @@ func (s *userService) GetUserByID(c *fiber.Ctx, id string) (*model.User, error) return user, result.Error } -func (s *userService) GetUserByEmail(c *fiber.Ctx, email string) (*model.User, error) { +func (s *UserService) GetUserByEmail(c *fiber.Ctx, email string) (*model.User, error) { user := new(model.User) result := s.DB.WithContext(c.Context()).Where("email = ?", email).First(user) @@ -100,7 +89,7 @@ func (s *userService) GetUserByEmail(c *fiber.Ctx, email string) (*model.User, e return user, result.Error } -func (s *userService) CreateUser(c *fiber.Ctx, req *validation.CreateUser) (*model.User, error) { +func (s *UserService) CreateUser(c *fiber.Ctx, req *validation.CreateUser) (*model.User, error) { if err := s.Validate.Struct(req); err != nil { return nil, err } @@ -131,7 +120,7 @@ func (s *userService) CreateUser(c *fiber.Ctx, req *validation.CreateUser) (*mod return user, result.Error } -func (s *userService) UpdateUser(c *fiber.Ctx, req *validation.UpdateUser, id string) (*model.User, error) { +func (s *UserService) UpdateUser(c *fiber.Ctx, req *validation.UpdateUser, id string) (*model.User, error) { if err := s.Validate.Struct(req); err != nil { return nil, err } @@ -176,7 +165,7 @@ func (s *userService) UpdateUser(c *fiber.Ctx, req *validation.UpdateUser, id st return user, result.Error } -func (s *userService) UpdatePassOrVerify(c *fiber.Ctx, req *validation.UpdatePassOrVerify, id string) error { +func (s *UserService) UpdatePassOrVerify(c *fiber.Ctx, req *validation.UpdatePassOrVerify, id string) error { if err := s.Validate.Struct(req); err != nil { return err } @@ -211,7 +200,7 @@ func (s *userService) UpdatePassOrVerify(c *fiber.Ctx, req *validation.UpdatePas return result.Error } -func (s *userService) DeleteUser(c *fiber.Ctx, id string) error { +func (s *UserService) DeleteUser(c *fiber.Ctx, id string) error { user := new(model.User) result := s.DB.WithContext(c.Context()).Delete(user, "id = ?", id) @@ -227,7 +216,7 @@ func (s *userService) DeleteUser(c *fiber.Ctx, id string) error { return result.Error } -func (s *userService) CreateGoogleUser(c *fiber.Ctx, req *validation.GoogleLogin) (*model.User, error) { +func (s *UserService) CreateGoogleUser(c *fiber.Ctx, req *validation.GoogleLogin) (*model.User, error) { if err := s.Validate.Struct(req); err != nil { return nil, err }