diff --git a/internal/app/app_verification.go b/internal/app/app_verification.go index 77fb873..d6f636b 100644 --- a/internal/app/app_verification.go +++ b/internal/app/app_verification.go @@ -75,12 +75,14 @@ func Run(cfg *config.Config) { CustomerServiceHost: cfg.CustomerRPCHost, })) - httpSrv := server.NewHTTP(cfg, logger).Register(cons.List()...) + httpSrv := server.NewHTTP(server.ServerConfig{ + Logger: logger, + Controllers: []server.Controller{cons.VerificationUser, cons.VerificationAdmin}, + }) go func() { - err := httpSrv.Start() - if err != nil { - logger.Fatal("CanNotServe", zap.Error(err)) + if err := httpSrv.Start(cfg.HttpAddress); err != nil { + logger.Fatal("Server startup error", zap.Error(err)) } }() diff --git a/internal/app/shutdown.go b/internal/app/shutdown.go index 3089373..0764770 100644 --- a/internal/app/shutdown.go +++ b/internal/app/shutdown.go @@ -10,7 +10,7 @@ import ( "syscall" ) -func gracefulShutdown(ctx context.Context, logger *zap.Logger, httpSrv *server.HTTP, mongoDB *mongo.Database) { +func gracefulShutdown(ctx context.Context, logger *zap.Logger, httpSrv *server.Server, mongoDB *mongo.Database) { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) killSignal := <-interrupt @@ -21,7 +21,7 @@ func gracefulShutdown(ctx context.Context, logger *zap.Logger, httpSrv *server.H logger.Info("AppTerminated") } - if err := httpSrv.Stop(); err != nil { + if err := httpSrv.Shutdown(ctx); err != nil { logger.Error("HttpServerShutdown", zap.Error(err)) } diff --git a/internal/controllers/admin/route.go b/internal/controllers/admin/route.go new file mode 100644 index 0000000..600bb95 --- /dev/null +++ b/internal/controllers/admin/route.go @@ -0,0 +1,12 @@ +package admin + +import "github.com/gofiber/fiber/v2" + +func (r *VerifyAdminController) Register(router fiber.Router) { + router.Get("/verification/:userID", r.GetVerification) + router.Patch("/verification", r.SetVerificationStatus) +} + +func (r *VerifyAdminController) Name() string { + return "" +} diff --git a/internal/controllers/admin/verification_admin.go b/internal/controllers/admin/verification_admin.go new file mode 100644 index 0000000..9966951 --- /dev/null +++ b/internal/controllers/admin/verification_admin.go @@ -0,0 +1,78 @@ +package admin + +import ( + "github.com/gofiber/fiber/v2" + "penahub.gitlab.yandexcloud.net/backend/verification/internal/models" + "penahub.gitlab.yandexcloud.net/backend/verification/internal/repository" + "penahub.gitlab.yandexcloud.net/backend/verification/pkg/validate_controllers" + "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients" +) + +type VerifyAdminControllerDeps struct { + Repository *repository.VerificationRepository + Customer *customer_clients.CustomersClient +} + +type VerifyAdminController struct { + repository *repository.VerificationRepository + customer *customer_clients.CustomersClient +} + +func NewVerificationAdminController(deps VerifyAdminControllerDeps) *VerifyAdminController { + return &VerifyAdminController{ + repository: deps.Repository, + customer: deps.Customer, + } +} + +func (r *VerifyAdminController) SetVerificationStatus(c *fiber.Ctx) error { + var req models.ReqSetVerification + + err := c.BodyParser(&req) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + errValidate := validate_controllers.ValidateStruct(&req) + if errValidate != nil { + return c.Status(fiber.StatusBadRequest).JSON(errValidate) + } + + updated, err := r.repository.Update(c.Context(), &models.Verification{ + ID: req.ID, + Accepted: req.Accepted, + Status: req.Status, + Comment: req.Comment, + TaxNumber: req.TaxNumber, + }) + + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + if req.Accepted { + _, err := r.customer.SetVerifyAccount(c.Context(), updated.UserID, req.Status) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + } + + return c.SendStatus(fiber.StatusOK) +} + +func (r *VerifyAdminController) GetVerification(c *fiber.Ctx) error { + userID := c.Params("userID") + if userID == "" { + return fiber.NewError(fiber.StatusUnauthorized) + } + + resp, err := r.repository.GetByUserID(c.Context(), userID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString(err.Error()) + } + + if resp == nil { + return c.SendStatus(fiber.StatusNotFound) + } + + return c.Status(fiber.StatusOK).JSON(resp) +} diff --git a/internal/controllers/user/route.go b/internal/controllers/user/route.go new file mode 100644 index 0000000..600b12a --- /dev/null +++ b/internal/controllers/user/route.go @@ -0,0 +1,13 @@ +package user + +import "github.com/gofiber/fiber/v2" + +func (r *VerifyUserController) Register(router fiber.Router) { + router.Get("/verification/create", r.GetVerification) + router.Post("/verification", r.CreateVerification) + router.Put("/verification", r.SetVerificationFile) +} + +func (r *VerifyUserController) Name() string { + return "" +} diff --git a/internal/controllers/verification.go b/internal/controllers/user/verification_user.go similarity index 61% rename from internal/controllers/verification.go rename to internal/controllers/user/verification_user.go index 427e31b..616f175 100644 --- a/internal/controllers/verification.go +++ b/internal/controllers/user/verification_user.go @@ -1,44 +1,37 @@ -package controllers +package user import ( "errors" - "mime/multipart" - "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients" - "github.com/gofiber/fiber/v2" "github.com/valyala/fasthttp" + "mime/multipart" "penahub.gitlab.yandexcloud.net/backend/verification/internal/client" "penahub.gitlab.yandexcloud.net/backend/verification/internal/models" "penahub.gitlab.yandexcloud.net/backend/verification/internal/repository" + "penahub.gitlab.yandexcloud.net/backend/verification/pkg/validate_controllers" ) -type VerificationController struct { +type VerifyUserControllerDeps struct { + Repository *repository.VerificationRepository + Telegram *client.Telegram +} + +type VerifyUserController struct { repository *repository.VerificationRepository telegram *client.Telegram - customer *customer_clients.CustomersClient } -func NewVerificationController(rep *repository.VerificationRepository, telegram *client.Telegram, customer *customer_clients.CustomersClient) *VerificationController { - return &VerificationController{repository: rep, telegram: telegram, customer: customer} -} - -func (r *VerificationController) GetRoutes() []Route { - return []Route{ - {"GET", "/verification/:userID", "GetVerification", r.GetVerification}, - {"POST", "/verification", "CreateVerification", r.CreateVerification}, - {"PATCH", "/verification", "SetVerificationStatus", r.SetVerificationStatus}, - {"PATCH", "/verification/file", "SetVerificationFile", r.SetVerificationFile}, +func NewVerificationUserController(deps VerifyUserControllerDeps) *VerifyUserController { + return &VerifyUserController{ + repository: deps.Repository, + telegram: deps.Telegram, } } -func (r *VerificationController) GetVerification(c *fiber.Ctx) error { - userID := c.Params("userID") - +func (r *VerifyUserController) GetVerification(c *fiber.Ctx) error { + userID := c.Locals("userID").(string) if userID == "" { - userID = c.Locals("userID").(string) - if userID == "" { - return fiber.NewError(fiber.StatusUnauthorized) - } + return fiber.NewError(fiber.StatusUnauthorized) } resp, err := r.repository.GetByUserID(c.Context(), userID) @@ -53,7 +46,7 @@ func (r *VerificationController) GetVerification(c *fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(resp) } -func (r *VerificationController) CreateVerification(c *fiber.Ctx) error { +func (r *VerifyUserController) CreateVerification(c *fiber.Ctx) error { var req models.ReqCreateVerification userID := c.Params("userID") @@ -71,7 +64,7 @@ func (r *VerificationController) CreateVerification(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } - errValidate := validateStruct(&req) + errValidate := validate_controllers.ValidateStruct(&req) if errValidate != nil { return c.Status(fiber.StatusBadRequest).JSON(errValidate) } @@ -126,41 +119,7 @@ func (r *VerificationController) CreateVerification(c *fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(result) } -func (r *VerificationController) SetVerificationStatus(c *fiber.Ctx) error { - var req models.ReqSetVerification - - err := c.BodyParser(&req) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - errValidate := validateStruct(&req) - if errValidate != nil { - return c.Status(fiber.StatusBadRequest).JSON(errValidate) - } - - updated, err := r.repository.Update(c.Context(), &models.Verification{ - ID: req.ID, - Accepted: req.Accepted, - Status: req.Status, - Comment: req.Comment, - TaxNumber: req.TaxNumber, - }) - - if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - if req.Accepted { - _, err := r.customer.SetVerifyAccount(c.Context(), updated.UserID, req.Status) - if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - } - - return c.SendStatus(fiber.StatusOK) -} - -func (r *VerificationController) SetVerificationFile(c *fiber.Ctx) error { +func (r *VerifyUserController) SetVerificationFile(c *fiber.Ctx) error { userID := c.Params("userID") baseURL := c.BaseURL() diff --git a/internal/controllers/verification_test.go b/internal/controllers/user/verification_user_test.go similarity index 95% rename from internal/controllers/verification_test.go rename to internal/controllers/user/verification_user_test.go index c797b12..8125ec1 100644 --- a/internal/controllers/verification_test.go +++ b/internal/controllers/user/verification_user_test.go @@ -1,11 +1,11 @@ -package controllers +package user import ( "github.com/stretchr/testify/suite" ) type VerificationTestSuite struct { - controller *VerificationController + controller *VerifyUserController suite.Suite } diff --git a/internal/initialize/controllers.go b/internal/initialize/controllers.go index de6684a..3c80a5e 100644 --- a/internal/initialize/controllers.go +++ b/internal/initialize/controllers.go @@ -2,34 +2,25 @@ package initialize import ( "penahub.gitlab.yandexcloud.net/backend/verification/internal/client" - "penahub.gitlab.yandexcloud.net/backend/verification/internal/controllers" + "penahub.gitlab.yandexcloud.net/backend/verification/internal/controllers/admin" + "penahub.gitlab.yandexcloud.net/backend/verification/internal/controllers/user" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients" - "reflect" ) -type Controller interface { - GetRoutes() []controllers.Route -} - type Controllers struct { - Verification *controllers.VerificationController -} - -func (c *Controllers) List() []Controller { - fields := reflect.ValueOf(c).Elem() - - var controllersArr []Controller - for i := 0; i < fields.NumField(); i++ { - vf := fields.Field(i) - - if vf.Type().Implements(reflect.TypeOf((*Controller)(nil)).Elem()) { - controllersArr = append(controllersArr, vf.Interface().(Controller)) - } - } - - return controllersArr + VerificationAdmin *admin.VerifyAdminController + VerificationUser *user.VerifyUserController } func NewControllers(reps *Repositories, telegram *client.Telegram, customer *customer_clients.CustomersClient) *Controllers { - return &Controllers{Verification: controllers.NewVerificationController(reps.Verification, telegram, customer)} + return &Controllers{ + VerificationAdmin: admin.NewVerificationAdminController(admin.VerifyAdminControllerDeps{ + Repository: reps.Verification, + Customer: customer, + }), + VerificationUser: user.NewVerificationUserController(user.VerifyUserControllerDeps{ + Repository: reps.Verification, + Telegram: telegram, + }), + } } diff --git a/internal/server/http.go b/internal/server/http.go index 176fbe1..c41a90d 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -1,21 +1,26 @@ package server import ( + "context" + "fmt" "github.com/gofiber/contrib/fiberzap" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/recover" "go.uber.org/zap" - "penahub.gitlab.yandexcloud.net/backend/verification/internal/config" - "penahub.gitlab.yandexcloud.net/backend/verification/internal/initialize" ) -type HTTP struct { - fiber *fiber.App - cfg *config.Config - logger *zap.Logger +type ServerConfig struct { + Logger *zap.Logger + Controllers []Controller } -func NewHTTP(cfg *config.Config, logger *zap.Logger) *HTTP { +type Server struct { + Logger *zap.Logger + Controllers []Controller + app *fiber.App +} + +func NewHTTP(cfg ServerConfig) *Server { srv := fiber.New(fiber.Config{ AppName: "Verification", ErrorHandler: fiber.DefaultErrorHandler, @@ -24,30 +29,51 @@ func NewHTTP(cfg *config.Config, logger *zap.Logger) *HTTP { srv.Use( recover.New(recover.Config{EnableStackTrace: true}), - fiberzap.New(fiberzap.Config{Logger: logger}), + fiberzap.New(fiberzap.Config{Logger: cfg.Logger}), LocalJwt(), Jwt(), ) - return &HTTP{fiber: srv, cfg: cfg, logger: logger} + s := &Server{ + Logger: cfg.Logger, + Controllers: cfg.Controllers, + app: srv, + } + + s.registerRoutes() + + return s } -// Register - автоматически регистрирует все контроллеры. -func (srv *HTTP) Register(controllers ...initialize.Controller) *HTTP { - for _, controller := range controllers { - for _, route := range controller.GetRoutes() { - srv.fiber.Add(route.Method, route.Path, route.Handler).Name(route.Name) +func (s *Server) Start(addr string) error { + if err := s.app.Listen(addr); err != nil { + s.Logger.Error("Failed to start server", zap.Error(err)) + return err + } + return nil +} + +func (s *Server) Shutdown(ctx context.Context) error { + return s.app.Shutdown() +} + +func (s *Server) registerRoutes() { + for _, c := range s.Controllers { + router := s.app.Group(c.Name()) + c.Register(router) + } +} + +type Controller interface { + Register(router fiber.Router) + Name() string +} + +func (s *Server) ListRoutes() { + fmt.Println("Registered routes:") + for _, stack := range s.app.Stack() { + for _, route := range stack { + fmt.Printf("%s %s\n", route.Method, route.Path) } } - return srv -} - -// Start - запускает http сервер. -func (srv *HTTP) Start() error { - return srv.fiber.Listen(srv.cfg.HttpAddress) -} - -// Stop - останавливает http сервер. -func (srv *HTTP) Stop() error { - return srv.fiber.Shutdown() } diff --git a/internal/controllers/controller.go b/pkg/validate_controllers/controller.go similarity index 92% rename from internal/controllers/controller.go rename to pkg/validate_controllers/controller.go index fb38106..04c3a8d 100644 --- a/internal/controllers/controller.go +++ b/pkg/validate_controllers/controller.go @@ -1,4 +1,4 @@ -package controllers +package validate_controllers import ( "reflect" @@ -18,7 +18,7 @@ type Route struct { } // validateStruct - возвращает строку с ошибкой, если структура не прошла валидацию. -func validateStruct(s any) []*models.RespErrorValidate { +func ValidateStruct(s any) []*models.RespErrorValidate { err := validate.Struct(s) var errorsValidate []*models.RespErrorValidate