some rework initialization api and separate controllers

This commit is contained in:
Pavel 2024-05-26 18:32:07 +03:00
parent 83b20bd5b8
commit fb51a1acf6
10 changed files with 199 additions and 118 deletions

@ -75,12 +75,14 @@ func Run(cfg *config.Config) {
CustomerServiceHost: cfg.CustomerRPCHost, 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() { go func() {
err := httpSrv.Start() if err := httpSrv.Start(cfg.HttpAddress); err != nil {
if err != nil { logger.Fatal("Server startup error", zap.Error(err))
logger.Fatal("CanNotServe", zap.Error(err))
} }
}() }()

@ -10,7 +10,7 @@ import (
"syscall" "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) interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
killSignal := <-interrupt killSignal := <-interrupt
@ -21,7 +21,7 @@ func gracefulShutdown(ctx context.Context, logger *zap.Logger, httpSrv *server.H
logger.Info("AppTerminated") logger.Info("AppTerminated")
} }
if err := httpSrv.Stop(); err != nil { if err := httpSrv.Shutdown(ctx); err != nil {
logger.Error("HttpServerShutdown", zap.Error(err)) logger.Error("HttpServerShutdown", zap.Error(err))
} }

@ -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 ""
}

@ -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)
}

@ -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 ""
}

@ -1,44 +1,37 @@
package controllers package user
import ( import (
"errors" "errors"
"mime/multipart"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"mime/multipart"
"penahub.gitlab.yandexcloud.net/backend/verification/internal/client" "penahub.gitlab.yandexcloud.net/backend/verification/internal/client"
"penahub.gitlab.yandexcloud.net/backend/verification/internal/models" "penahub.gitlab.yandexcloud.net/backend/verification/internal/models"
"penahub.gitlab.yandexcloud.net/backend/verification/internal/repository" "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 repository *repository.VerificationRepository
telegram *client.Telegram telegram *client.Telegram
customer *customer_clients.CustomersClient
} }
func NewVerificationController(rep *repository.VerificationRepository, telegram *client.Telegram, customer *customer_clients.CustomersClient) *VerificationController { func NewVerificationUserController(deps VerifyUserControllerDeps) *VerifyUserController {
return &VerificationController{repository: rep, telegram: telegram, customer: customer} return &VerifyUserController{
} repository: deps.Repository,
telegram: deps.Telegram,
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 (r *VerificationController) GetVerification(c *fiber.Ctx) error { func (r *VerifyUserController) GetVerification(c *fiber.Ctx) error {
userID := c.Params("userID") userID := c.Locals("userID").(string)
if userID == "" { if userID == "" {
userID = c.Locals("userID").(string) return fiber.NewError(fiber.StatusUnauthorized)
if userID == "" {
return fiber.NewError(fiber.StatusUnauthorized)
}
} }
resp, err := r.repository.GetByUserID(c.Context(), userID) 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) 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 var req models.ReqCreateVerification
userID := c.Params("userID") userID := c.Params("userID")
@ -71,7 +64,7 @@ func (r *VerificationController) CreateVerification(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, err.Error()) return fiber.NewError(fiber.StatusBadRequest, err.Error())
} }
errValidate := validateStruct(&req) errValidate := validate_controllers.ValidateStruct(&req)
if errValidate != nil { if errValidate != nil {
return c.Status(fiber.StatusBadRequest).JSON(errValidate) 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) return c.Status(fiber.StatusOK).JSON(result)
} }
func (r *VerificationController) SetVerificationStatus(c *fiber.Ctx) error { func (r *VerifyUserController) SetVerificationFile(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 {
userID := c.Params("userID") userID := c.Params("userID")
baseURL := c.BaseURL() baseURL := c.BaseURL()

@ -1,11 +1,11 @@
package controllers package user
import ( import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
type VerificationTestSuite struct { type VerificationTestSuite struct {
controller *VerificationController controller *VerifyUserController
suite.Suite suite.Suite
} }

@ -2,34 +2,25 @@ package initialize
import ( import (
"penahub.gitlab.yandexcloud.net/backend/verification/internal/client" "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" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients"
"reflect"
) )
type Controller interface {
GetRoutes() []controllers.Route
}
type Controllers struct { type Controllers struct {
Verification *controllers.VerificationController VerificationAdmin *admin.VerifyAdminController
} VerificationUser *user.VerifyUserController
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
} }
func NewControllers(reps *Repositories, telegram *client.Telegram, customer *customer_clients.CustomersClient) *Controllers { 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,
}),
}
} }

@ -1,21 +1,26 @@
package server package server
import ( import (
"context"
"fmt"
"github.com/gofiber/contrib/fiberzap" "github.com/gofiber/contrib/fiberzap"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/recover"
"go.uber.org/zap" "go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/backend/verification/internal/config"
"penahub.gitlab.yandexcloud.net/backend/verification/internal/initialize"
) )
type HTTP struct { type ServerConfig struct {
fiber *fiber.App Logger *zap.Logger
cfg *config.Config Controllers []Controller
logger *zap.Logger
} }
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{ srv := fiber.New(fiber.Config{
AppName: "Verification", AppName: "Verification",
ErrorHandler: fiber.DefaultErrorHandler, ErrorHandler: fiber.DefaultErrorHandler,
@ -24,30 +29,51 @@ func NewHTTP(cfg *config.Config, logger *zap.Logger) *HTTP {
srv.Use( srv.Use(
recover.New(recover.Config{EnableStackTrace: true}), recover.New(recover.Config{EnableStackTrace: true}),
fiberzap.New(fiberzap.Config{Logger: logger}), fiberzap.New(fiberzap.Config{Logger: cfg.Logger}),
LocalJwt(), LocalJwt(),
Jwt(), 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 (s *Server) Start(addr string) error {
func (srv *HTTP) Register(controllers ...initialize.Controller) *HTTP { if err := s.app.Listen(addr); err != nil {
for _, controller := range controllers { s.Logger.Error("Failed to start server", zap.Error(err))
for _, route := range controller.GetRoutes() { return err
srv.fiber.Add(route.Method, route.Path, route.Handler).Name(route.Name) }
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()
} }

@ -1,4 +1,4 @@
package controllers package validate_controllers
import ( import (
"reflect" "reflect"
@ -18,7 +18,7 @@ type Route struct {
} }
// validateStruct - возвращает строку с ошибкой, если структура не прошла валидацию. // validateStruct - возвращает строку с ошибкой, если структура не прошла валидацию.
func validateStruct(s any) []*models.RespErrorValidate { func ValidateStruct(s any) []*models.RespErrorValidate {
err := validate.Struct(s) err := validate.Struct(s)
var errorsValidate []*models.RespErrorValidate var errorsValidate []*models.RespErrorValidate