add base logic for promo created

This commit is contained in:
Pavel 2024-01-11 21:20:33 +03:00
parent 95559a0fda
commit f3df811c9b
7 changed files with 85 additions and 39 deletions

@ -1,8 +1,8 @@
package app package app
import ( import (
promocontroller "codeword/internal/controller/promocode" "codeword/internal/controller/promocode"
reccontroller "codeword/internal/controller/recovery" "codeword/internal/controller/recovery"
"codeword/internal/initialize" "codeword/internal/initialize"
"codeword/internal/repository" "codeword/internal/repository"
httpserver "codeword/internal/server/http" httpserver "codeword/internal/server/http"
@ -26,9 +26,9 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
rdb, err := initialize.Redis(ctx, cfg) rdb, err := initialize.Redis(ctx, cfg)
encrypt := initialize.Encrypt(cfg) encrypt := initialize.Encrypt(cfg)
promoCodeRepo := repository.NewPromoCodeRepository(mdb.Collection("promoCodes"))
codewordRepo := repository.NewCodewordRepository(repository.Deps{Rdb: rdb, Mdb: mdb.Collection("codeword")}) codewordRepo := repository.NewCodewordRepository(repository.Deps{Rdb: rdb, Mdb: mdb.Collection("codeword")})
userRepo := repository.NewUserRepository(repository.Deps{Rdb: nil, Mdb: mdb.Collection("users")}) userRepo := repository.NewUserRepository(repository.Deps{Rdb: nil, Mdb: mdb.Collection("users")})
promoCodeRepo := repository.NewPromoCodeRepository(mdb.Collection("promocodes"))
recoveryEmailSender := initialize.RecoveryEmailSender(cfg, logger) recoveryEmailSender := initialize.RecoveryEmailSender(cfg, logger)
authClient := initialize.AuthClient(cfg, logger) authClient := initialize.AuthClient(cfg, logger)
@ -46,8 +46,8 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
PromoCodeRepo: promoCodeRepo, PromoCodeRepo: promoCodeRepo,
}) })
recoveryController := reccontroller.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL) recoveryController := recovery.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL)
promoCodeController := promocontroller.NewPromoCodeController(logger, promoService) promoCodeController := promocode.NewPromoCodeController(logger, promoService)
recoveryWC := recovery_worker.NewRecoveryWC(recovery_worker.Deps{ recoveryWC := recovery_worker.NewRecoveryWC(recovery_worker.Deps{
Logger: logger, Logger: logger,

@ -1,8 +1,10 @@
package controller package promocode
import ( import (
"codeword/internal/models" "codeword/internal/models"
"codeword/internal/repository"
"codeword/internal/services" "codeword/internal/services"
"errors"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -28,6 +30,11 @@ func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error {
createdPromoCode, err := p.promoCodeService.CreatePromoCode(c.Context(), &reqCreatePromoCode) createdPromoCode, err := p.promoCodeService.CreatePromoCode(c.Context(), &reqCreatePromoCode)
if err != nil { if err != nil {
p.logger.Error("Failed to create promocode", zap.Error(err)) p.logger.Error("Failed to create promocode", zap.Error(err))
if errors.Is(err, repository.ErrDuplicateCodeword) {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Duplicate Codeword"})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }

@ -1,4 +1,4 @@
package controller package recovery
import ( import (
"codeword/internal/models" "codeword/internal/models"

@ -1,28 +1,31 @@
package models package models
import "time" import (
"go.mongodb.org/mongo-driver/bson/primitive"
"time"
)
type PromoCode struct { type PromoCode struct {
ID string `json:"id"` ID primitive.ObjectID `json:"id" bson:"_id"`
Codeword string `json:"codeword"` // то, что будет вводить пользователь, чтобы получить плюшки Codeword string `json:"codeword" bson:"codeword"` // то, что будет вводить пользователь, чтобы получить плюшки
Description string `json:"description"` // описание, необходимое менеджеру в админке Description string `json:"description" bson:"description"` // описание, необходимое менеджеру в админке
Greetings string `json:"greetings"` // текст, выдаваемый пользователю в ответ на активацию промокода Greetings string `json:"greetings" bson:"greetings"` // текст, выдаваемый пользователю в ответ на активацию промокода
DueTo int64 `json:"dueTo"` // таймштамп времени окончания работы активации промокода DueTo int64 `json:"dueTo" bson:"dueTo"` // таймштамп времени окончания работы активации промокода
ActivationCount int64 `json:"activationCount"` // предел количества активаций промокода ActivationCount int64 `json:"activationCount" bson:"activationCount"` // предел количества активаций промокода
Bonus struct { Bonus struct {
Privilege struct { Privilege struct {
PrivilegeID string `json:"privilegeID"` // айдишник привилегии, которая будет выдаваться PrivilegeID string `json:"privilegeID" bson:"privilegeID"` // айдишник привилегии, которая будет выдаваться
Amount uint64 `json:"amount"` // количество Amount uint64 `json:"amount" bson:"amount"` // количество
} `json:"privilege"` } `json:"privilege" bson:"privilege"`
Discount struct { Discount struct {
Layer int `json:"layer"` // 1|2 Layer int `json:"layer" bson:"layer"` // 1|2
Factor float64 `json:"factor"` // процент скидки, вернее множитель, при котором достигается этот процент скидки Factor float64 `json:"factor" bson:"factor"` // процент скидки, вернее множитель, при котором достигается этот процент скидки
Target string `json:"target"` // PrivilegeID или ServiceKey в зависимости от слоя Target string `json:"target" bson:"target"` // PrivilegeID или ServiceKey в зависимости от слоя
Threshold int64 `json:"threshold"` // граничное значение, при пересечении которого применяется эта скидка Threshold int64 `json:"threshold" bson:"threshold"` // граничное значение, при пересечении которого применяется эта скидка
} `json:"discount"` } `json:"discount" bson:"discount"`
} `json:"bonus"` } `json:"bonus" bson:"bonus"`
Outdated bool `json:"outdated"` Outdated bool `json:"outdated" bson:"outdated"`
OffLimit bool `json:"offLimit"` OffLimit bool `json:"offLimit" bson:"offLimit"`
Delete bool `json:"delete"` Delete bool `json:"delete" bson:"delete"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
} }

@ -3,23 +3,52 @@ package repository
import ( import (
"codeword/internal/models" "codeword/internal/models"
"context" "context"
"errors"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"time" "time"
) )
var ErrDuplicateCodeword = errors.New("duplicate codeword")
type PromoCodeRepository struct { type PromoCodeRepository struct {
mdb *mongo.Collection mdb *mongo.Collection
} }
func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository { func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository {
indexModel := mongo.IndexModel{
Keys: bson.D{
{"codeword", 1},
{"delete", 1},
},
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"delete": false}),
}
_, err := mdb.Indexes().CreateOne(context.Background(), indexModel)
if err != nil {
panic(err)
}
return &PromoCodeRepository{mdb: mdb} return &PromoCodeRepository{mdb: mdb}
} }
func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error) { func (r *PromoCodeRepository) CreatePromo(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error) {
promoCode.CreatedAt = time.Now() promoCode.CreatedAt = time.Now()
promoCode.ID = primitive.NewObjectID()
_, err := r.mdb.InsertOne(ctx, promoCode) _, err := r.mdb.InsertOne(ctx, promoCode)
if err != nil { if err != nil {
if writeErr, ok := err.(mongo.WriteException); ok {
for _, writeError := range writeErr.WriteErrors {
if writeError.Code == 11000 {
return nil, ErrDuplicateCodeword
}
}
}
return nil, err return nil, err
} }
return promoCode, nil return promoCode, nil
} }

@ -1,8 +1,8 @@
package http package http
import ( import (
promocontroller "codeword/internal/controller/promocode" "codeword/internal/controller/promocode"
reccontroller "codeword/internal/controller/recovery" "codeword/internal/controller/recovery"
"context" "context"
"fmt" "fmt"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
@ -12,14 +12,14 @@ import (
type ServerConfig struct { type ServerConfig struct {
Logger *zap.Logger Logger *zap.Logger
RecoveryController *reccontroller.RecoveryController RecoveryController *recovery.RecoveryController
PromoCodeController *promocontroller.PromoCodeController PromoCodeController *promocode.PromoCodeController
} }
type Server struct { type Server struct {
Logger *zap.Logger Logger *zap.Logger
RecoveryController *reccontroller.RecoveryController RecoveryController *recovery.RecoveryController
PromoCodeController *promocontroller.PromoCodeController PromoCodeController *promocode.PromoCodeController
app *fiber.App app *fiber.App
} }
@ -27,9 +27,10 @@ func NewServer(config ServerConfig) *Server {
app := fiber.New() app := fiber.New()
s := &Server{ s := &Server{
Logger: config.Logger, Logger: config.Logger,
RecoveryController: config.RecoveryController, RecoveryController: config.RecoveryController,
app: app, PromoCodeController: config.PromoCodeController,
app: app,
} }
s.registerRoutes() s.registerRoutes()

@ -7,7 +7,7 @@ import (
) )
type PromoCodeRepository interface { type PromoCodeRepository interface {
CreatePromoCode(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error) CreatePromo(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error)
} }
type PromoDeps struct { type PromoDeps struct {
@ -28,5 +28,11 @@ func NewPromoCodeService(deps PromoDeps) *PromoCodeService {
} }
func (s *PromoCodeService) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) { func (s *PromoCodeService) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) {
return nil, nil promoCode, err := s.promoCodeRepo.CreatePromo(ctx, req)
if err != nil {
s.logger.Error("Failed to add promocode in database", zap.Error(err))
return nil, err
}
return promoCode, nil
} }