diff --git a/internal/app/app.go b/internal/app/app.go index 112ded4..80368e6 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -1,7 +1,8 @@ package app import ( - controller "codeword/internal/controller/recovery" + promocontroller "codeword/internal/controller/promocode" + reccontroller "codeword/internal/controller/recovery" "codeword/internal/initialize" "codeword/internal/repository" httpserver "codeword/internal/server/http" @@ -24,8 +25,11 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { rdb, err := initialize.Redis(ctx, cfg) encrypt := initialize.Encrypt(cfg) + codewordRepo := repository.NewCodewordRepository(repository.Deps{Rdb: rdb, Mdb: mdb.Collection("codeword")}) userRepo := repository.NewUserRepository(repository.Deps{Rdb: nil, Mdb: mdb.Collection("users")}) + promoCodeRepo := repository.NewPromoCodeRepository(mdb.Collection("promocodes")) + recoveryEmailSender := initialize.RecoveryEmailSender(cfg, logger) authClient := initialize.AuthClient(cfg, logger) @@ -37,7 +41,13 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { AuthClient: authClient, }) - recoveryController := controller.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL) + promoService := services.NewPromoCodeService(services.PromoDeps{ + Logger: logger, + PromoCodeRepo: promoCodeRepo, + }) + + recoveryController := reccontroller.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL) + promoCodeController := promocontroller.NewPromoCodeController(logger, promoService) recoveryWC := recovery_worker.NewRecoveryWC(recovery_worker.Deps{ Logger: logger, @@ -55,8 +65,9 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { go purgeWC.Start(ctx) server := httpserver.NewServer(httpserver.ServerConfig{ - Logger: logger, - RecoveryController: recoveryController, + Logger: logger, + RecoveryController: recoveryController, + PromoCodeController: promoCodeController, }) go func() { diff --git a/internal/controller/promocode/promocode_controller.go b/internal/controller/promocode/promocode_controller.go new file mode 100644 index 0000000..415cb5f --- /dev/null +++ b/internal/controller/promocode/promocode_controller.go @@ -0,0 +1,35 @@ +package controller + +import ( + "codeword/internal/models" + "codeword/internal/services" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +type PromoCodeController struct { + logger *zap.Logger + promoCodeService *services.PromoCodeService +} + +func NewPromoCodeController(logger *zap.Logger, promoCodeService *services.PromoCodeService) *PromoCodeController { + return &PromoCodeController{ + logger: logger, + promoCodeService: promoCodeService, + } +} + +func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error { + var reqCreatePromoCode models.PromoCode + if err := c.BodyParser(&reqCreatePromoCode); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"}) + } + + createdPromoCode, err := p.promoCodeService.CreatePromoCode(c.Context(), &reqCreatePromoCode) + if err != nil { + p.logger.Error("Failed to create promocode", zap.Error(err)) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) + } + + return c.Status(fiber.StatusCreated).JSON(createdPromoCode) +} diff --git a/internal/models/bonus.go b/internal/models/bonus.go new file mode 100644 index 0000000..394c844 --- /dev/null +++ b/internal/models/bonus.go @@ -0,0 +1,28 @@ +package models + +import "time" + +type PromoCode struct { + ID string `json:"id"` + Codeword string `json:"codeword"` // то, что будет вводить пользователь, чтобы получить плюшки + Description string `json:"description"` // описание, необходимое менеджеру в админке + Greetings string `json:"greetings"` // текст, выдаваемый пользователю в ответ на активацию промокода + DueTo int64 `json:"dueTo"` // таймштамп времени окончания работы активации промокода + ActivationCount int64 `json:"activationCount"` // предел количества активаций промокода + Bonus struct { + Privilege struct { + PrivilegeID string `json:"privilegeID"` // айдишник привилегии, которая будет выдаваться + Amount uint64 `json:"amount"` // количество + } `json:"privilege"` + Discount struct { + Layer int `json:"layer"` // 1|2 + Factor float64 `json:"factor"` // процент скидки, вернее множитель, при котором достигается этот процент скидки + Target string `json:"target"` // PrivilegeID или ServiceKey в зависимости от слоя + Threshold int64 `json:"threshold"` // граничное значение, при пересечении которого применяется эта скидка + } `json:"discount"` + } `json:"bonus"` + Outdated bool `json:"outdated"` + OffLimit bool `json:"offLimit"` + Delete bool `json:"delete"` + CreatedAt time.Time `json:"createdAt"` +} diff --git a/internal/repository/codeword_repository.go b/internal/repository/codeword_repository.go index 75d38e1..1b134fa 100644 --- a/internal/repository/codeword_repository.go +++ b/internal/repository/codeword_repository.go @@ -12,18 +12,18 @@ import ( "time" ) -type codewordRepository struct { +type CodewordRepository struct { mdb *mongo.Collection rdb *redis.Client } -func NewCodewordRepository(deps Deps) *codewordRepository { +func NewCodewordRepository(deps Deps) *CodewordRepository { - return &codewordRepository{mdb: deps.Mdb, rdb: deps.Rdb} + return &CodewordRepository{mdb: deps.Mdb, rdb: deps.Rdb} } // сохраняем полученные данные о пользователе и подписи в бд -func (r *codewordRepository) StoreRecoveryRecord(ctx context.Context, deps models.StoreRecDeps) (string, error) { +func (r *CodewordRepository) StoreRecoveryRecord(ctx context.Context, deps models.StoreRecDeps) (string, error) { newID := primitive.NewObjectID() signID := deps.Key + newID.Hex() record := models.RestoreRequest{ @@ -45,7 +45,7 @@ func (r *codewordRepository) StoreRecoveryRecord(ctx context.Context, deps model } // добавляем в очередь данные для отправки на почту в редис -func (r *codewordRepository) InsertToQueue(ctx context.Context, deps models.RecEmailDeps) error { +func (r *CodewordRepository) InsertToQueue(ctx context.Context, deps models.RecEmailDeps) error { task := models.RecoveryRecord{ ID: deps.ID, UserID: deps.UserID, @@ -66,7 +66,7 @@ func (r *codewordRepository) InsertToQueue(ctx context.Context, deps models.RecE } // получаем данные юзера по подписи -func (r *codewordRepository) GetRecoveryRecord(ctx context.Context, key string) (*models.RestoreRequest, error) { +func (r *CodewordRepository) GetRecoveryRecord(ctx context.Context, key string) (*models.RestoreRequest, error) { var restoreRequest models.RestoreRequest filter := bson.M{"sign_id": key} @@ -80,7 +80,7 @@ func (r *codewordRepository) GetRecoveryRecord(ctx context.Context, key string) } // пингует в монгу чтобы проверить подключение -func (r *codewordRepository) Ping(ctx context.Context) error { +func (r *CodewordRepository) Ping(ctx context.Context) error { if err := r.mdb.Database().Client().Ping(ctx, readpref.Primary()); err != nil { return err } diff --git a/internal/repository/promocode_repository.go b/internal/repository/promocode_repository.go new file mode 100644 index 0000000..0b3dff3 --- /dev/null +++ b/internal/repository/promocode_repository.go @@ -0,0 +1,25 @@ +package repository + +import ( + "codeword/internal/models" + "context" + "go.mongodb.org/mongo-driver/mongo" + "time" +) + +type PromoCodeRepository struct { + mdb *mongo.Collection +} + +func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository { + return &PromoCodeRepository{mdb: mdb} +} + +func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error) { + promoCode.CreatedAt = time.Now() + _, err := r.mdb.InsertOne(ctx, promoCode) + if err != nil { + return nil, err + } + return promoCode, nil +} diff --git a/internal/repository/user_repository.go b/internal/repository/user_repository.go index 3b2e2c7..3403afb 100644 --- a/internal/repository/user_repository.go +++ b/internal/repository/user_repository.go @@ -13,17 +13,17 @@ type Deps struct { Rdb *redis.Client } -type userRepository struct { +type UserRepository struct { mdb *mongo.Collection } -func NewUserRepository(deps Deps) *userRepository { +func NewUserRepository(deps Deps) *UserRepository { - return &userRepository{mdb: deps.Mdb} + return &UserRepository{mdb: deps.Mdb} } // ищем пользователя по мейлу в коллекции users -func (r *userRepository) FindByEmail(ctx context.Context, email string) (*models.User, error) { +func (r *UserRepository) FindByEmail(ctx context.Context, email string) (*models.User, error) { var user models.User err := r.mdb.FindOne(ctx, bson.M{"email": email}).Decode(&user) diff --git a/internal/server/http/http_server.go b/internal/server/http/http_server.go index ca397ff..8326c9b 100644 --- a/internal/server/http/http_server.go +++ b/internal/server/http/http_server.go @@ -1,7 +1,8 @@ package http import ( - controller "codeword/internal/controller/recovery" + promocontroller "codeword/internal/controller/promocode" + reccontroller "codeword/internal/controller/recovery" "context" "fmt" "github.com/gofiber/fiber/v2" @@ -10,14 +11,16 @@ import ( ) type ServerConfig struct { - Logger *zap.Logger - RecoveryController *controller.RecoveryController + Logger *zap.Logger + RecoveryController *reccontroller.RecoveryController + PromoCodeController *promocontroller.PromoCodeController } type Server struct { - Logger *zap.Logger - RecoveryController *controller.RecoveryController - app *fiber.App + Logger *zap.Logger + RecoveryController *reccontroller.RecoveryController + PromoCodeController *promocontroller.PromoCodeController + app *fiber.App } func NewServer(config ServerConfig) *Server { @@ -52,6 +55,8 @@ func (s *Server) registerRoutes() { s.app.Post("/recover", s.RecoveryController.HandleRecoveryRequest) s.app.Get("/recover/:sign", s.RecoveryController.HandleRecoveryLink) + + s.app.Post("/promocode/create", s.PromoCodeController.CreatePromoCode) //... other } diff --git a/internal/services/promocode_service.go b/internal/services/promocode_service.go new file mode 100644 index 0000000..119714d --- /dev/null +++ b/internal/services/promocode_service.go @@ -0,0 +1,32 @@ +package services + +import ( + "codeword/internal/models" + "context" + "go.uber.org/zap" +) + +type PromoCodeRepository interface { + CreatePromoCode(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error) +} + +type PromoDeps struct { + Logger *zap.Logger + PromoCodeRepo PromoCodeRepository +} + +type PromoCodeService struct { + logger *zap.Logger + promoCodeRepo PromoCodeRepository +} + +func NewPromoCodeService(deps PromoDeps) *PromoCodeService { + return &PromoCodeService{ + logger: deps.Logger, + promoCodeRepo: deps.PromoCodeRepo, + } +} + +func (s *PromoCodeService) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) { + return nil, nil +}