Merge branch 'promoList' into 'dev'
Promo list See merge request pena-services/codeword!8
This commit is contained in:
commit
fd8c986e22
@ -165,6 +165,34 @@ paths:
|
||||
error:
|
||||
type: string
|
||||
|
||||
/promocode/getList:
|
||||
post:
|
||||
summary: Получить список промокодов
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GetPromoCodesListReq'
|
||||
responses:
|
||||
'200':
|
||||
description: Список промокодов и общее количество успешно получены
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GetPromoCodesListResp'
|
||||
'400':
|
||||
description: Неверный запрос из-за невалидных данных
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
'500':
|
||||
description: Внутренняя ошибка сервера
|
||||
|
||||
|
||||
components:
|
||||
schemas:
|
||||
@ -298,3 +326,40 @@ components:
|
||||
description: Флаг удаления промокода
|
||||
required:
|
||||
- id
|
||||
GetPromoCodesListReq:
|
||||
type: object
|
||||
required:
|
||||
- page
|
||||
- limit
|
||||
- filter
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
description: Номер страницы выборки, начиная с 0
|
||||
limit:
|
||||
type: integer
|
||||
description: Размер страницы выборки
|
||||
filter:
|
||||
$ref: '#/components/schemas/GetPromoCodesListReqFilter'
|
||||
|
||||
GetPromoCodesListReqFilter:
|
||||
type: object
|
||||
properties:
|
||||
text:
|
||||
type: string
|
||||
description: Полнотекстовый поиск по полям Codeword, Description, Greetings
|
||||
active:
|
||||
type: boolean
|
||||
description: Если true, выбираются записи, где delete, outdated и offLimit равны false
|
||||
|
||||
GetPromoCodesListResp:
|
||||
type: object
|
||||
properties:
|
||||
count:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Общее количество промокодов в выборке
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/PromoCodeResponse'
|
@ -22,12 +22,12 @@ func NewPromoCodeController(logger *zap.Logger, promoCodeService *services.Promo
|
||||
}
|
||||
|
||||
func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error {
|
||||
var reqCreatePromoCode models.PromoCode
|
||||
if err := c.BodyParser(&reqCreatePromoCode); err != nil {
|
||||
var req models.PromoCode
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"})
|
||||
}
|
||||
|
||||
createdPromoCode, err := p.promoCodeService.CreatePromoCode(c.Context(), &reqCreatePromoCode)
|
||||
createdPromoCode, err := p.promoCodeService.CreatePromoCode(c.Context(), &req)
|
||||
if err != nil {
|
||||
p.logger.Error("Failed to create promocode", zap.Error(err))
|
||||
|
||||
@ -42,16 +42,16 @@ func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error {
|
||||
var reqEditPromoCode models.ReqEditPromoCode
|
||||
if err := c.BodyParser(&reqEditPromoCode); err != nil {
|
||||
var req models.ReqEditPromoCode
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"})
|
||||
}
|
||||
|
||||
if reqEditPromoCode.ID == "" {
|
||||
if req.ID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "promocode ID is required"})
|
||||
}
|
||||
|
||||
editedPromoCode, err := p.promoCodeService.EditPromoCode(c.Context(), &reqEditPromoCode)
|
||||
editedPromoCode, err := p.promoCodeService.EditPromoCode(c.Context(), &req)
|
||||
if err != nil {
|
||||
p.logger.Error("Failed to edit promocode", zap.Error(err))
|
||||
|
||||
@ -64,3 +64,22 @@ func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error {
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(editedPromoCode)
|
||||
}
|
||||
|
||||
func (p *PromoCodeController) GetList(c *fiber.Ctx) error {
|
||||
var req models.GetPromoCodesListReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"})
|
||||
}
|
||||
|
||||
promoCodes, count, err := p.promoCodeService.GetPromoCodesList(c.Context(), &req)
|
||||
if err != nil {
|
||||
p.logger.Error("Failed to retrieve promocode list", zap.Error(err))
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
|
||||
}
|
||||
|
||||
resp := models.GetPromoCodesListResp{
|
||||
Count: count,
|
||||
Items: promoCodes,
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(resp)
|
||||
}
|
||||
|
@ -40,3 +40,19 @@ type ReqEditPromoCode struct {
|
||||
|
||||
Delete *bool `json:"delete,omitempty" bson:"delete"`
|
||||
}
|
||||
|
||||
type GetPromoCodesListReqFilter struct {
|
||||
Text string `json:"text"` // полнотекстовый поиск пo Codeword, Decription, Greetings полям
|
||||
Active bool `json:"active"` // если true, то выбирать deleted==false && outdated== false && offlimit == false
|
||||
}
|
||||
|
||||
type GetPromoCodesListReq struct {
|
||||
Page int `json:"page"` //номер страницы выборки. начинается с 0. по сути, skip для выборки из mongodb
|
||||
Limit int `json:"limit"` //размер страницы выборки. больше 10, меньше 250. отвечает за skip = page*limit, и за limit
|
||||
Filter GetPromoCodesListReqFilter `json:"filter"`
|
||||
}
|
||||
|
||||
type GetPromoCodesListResp struct {
|
||||
Count int64 `json:"count"` // количество в выборке всего
|
||||
Items []PromoCode `json:"items"` // "страница" промокодов
|
||||
}
|
||||
|
@ -16,19 +16,39 @@ var (
|
||||
ErrPromoCodeNotFound = errors.New("promo code not found")
|
||||
)
|
||||
|
||||
// структура для горутины чтобы ошибки не пропускать
|
||||
type countResult struct {
|
||||
count int64
|
||||
err error
|
||||
}
|
||||
|
||||
type PromoCodeRepository struct {
|
||||
mdb *mongo.Collection
|
||||
}
|
||||
|
||||
func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository {
|
||||
indexModel := mongo.IndexModel{
|
||||
// todo заменить паники вроде как в роде не круто их юзать
|
||||
uniqueIndexModel := mongo.IndexModel{
|
||||
Keys: bson.D{
|
||||
{"codeword", 1},
|
||||
{"delete", 1},
|
||||
{Key: "codeword", Value: 1},
|
||||
{Key: "delete", Value: 1},
|
||||
},
|
||||
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"delete": false}),
|
||||
}
|
||||
_, err := mdb.Indexes().CreateOne(context.Background(), indexModel)
|
||||
_, err := mdb.Indexes().CreateOne(context.Background(), uniqueIndexModel)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
textIndexModel := mongo.IndexModel{
|
||||
Keys: bson.D{
|
||||
{Key: "codeword", Value: "text"},
|
||||
{Key: "description", Value: "text"},
|
||||
{Key: "greetings", Value: "text"},
|
||||
},
|
||||
Options: options.Index().SetName("TextIndex"),
|
||||
}
|
||||
_, err = mdb.Indexes().CreateOne(context.Background(), textIndexModel)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -36,11 +56,11 @@ 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()
|
||||
promoCode.ID = primitive.NewObjectID()
|
||||
func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) {
|
||||
req.CreatedAt = time.Now()
|
||||
req.ID = primitive.NewObjectID()
|
||||
|
||||
_, err := r.mdb.InsertOne(ctx, promoCode)
|
||||
_, err := r.mdb.InsertOne(ctx, req)
|
||||
if err != nil {
|
||||
if writeErr, ok := err.(mongo.WriteException); ok {
|
||||
for _, writeError := range writeErr.WriteErrors {
|
||||
@ -53,30 +73,30 @@ func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, promoCode *mo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return promoCode, nil
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (r *PromoCodeRepository) EditPromoCode(ctx context.Context, editPromoCode *models.ReqEditPromoCode) (*models.PromoCode, error) {
|
||||
promoCodeID, err := primitive.ObjectIDFromHex(editPromoCode.ID)
|
||||
func (r *PromoCodeRepository) EditPromoCode(ctx context.Context, req *models.ReqEditPromoCode) (*models.PromoCode, error) {
|
||||
promoCodeID, err := primitive.ObjectIDFromHex(req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateFields := bson.M{}
|
||||
if editPromoCode.Description != nil {
|
||||
updateFields["description"] = *editPromoCode.Description
|
||||
if req.Description != nil {
|
||||
updateFields["description"] = *req.Description
|
||||
}
|
||||
if editPromoCode.Greetings != nil {
|
||||
updateFields["greetings"] = *editPromoCode.Greetings
|
||||
if req.Greetings != nil {
|
||||
updateFields["greetings"] = *req.Greetings
|
||||
}
|
||||
if editPromoCode.DueTo != nil {
|
||||
updateFields["dueTo"] = *editPromoCode.DueTo
|
||||
if req.DueTo != nil {
|
||||
updateFields["dueTo"] = *req.DueTo
|
||||
}
|
||||
if editPromoCode.ActivationCount != nil {
|
||||
updateFields["activationCount"] = *editPromoCode.ActivationCount
|
||||
if req.ActivationCount != nil {
|
||||
updateFields["activationCount"] = *req.ActivationCount
|
||||
}
|
||||
if editPromoCode.Delete != nil {
|
||||
updateFields["delete"] = *editPromoCode.Delete
|
||||
if req.Delete != nil {
|
||||
updateFields["delete"] = *req.Delete
|
||||
}
|
||||
|
||||
if len(updateFields) == 0 {
|
||||
@ -109,3 +129,59 @@ func (r *PromoCodeRepository) GetPromoCodeByID(ctx context.Context, promoCodeID
|
||||
|
||||
return &promoCode, nil
|
||||
}
|
||||
|
||||
func (r *PromoCodeRepository) GetPromoCodesList(ctx context.Context, req *models.GetPromoCodesListReq) ([]models.PromoCode, int64, error) {
|
||||
filter := bson.M{}
|
||||
|
||||
if req.Filter.Text != "" {
|
||||
filter["$text"] = bson.M{"$search": req.Filter.Text}
|
||||
}
|
||||
|
||||
if req.Filter.Active {
|
||||
filter["delete"] = false
|
||||
filter["outdated"] = false
|
||||
filter["offLimit"] = false
|
||||
} else {
|
||||
filter["$or"] = []interface{}{
|
||||
bson.M{"delete": true},
|
||||
bson.M{"outdated": true},
|
||||
bson.M{"offLimit": true},
|
||||
}
|
||||
}
|
||||
|
||||
opt := options.Find().SetSkip(int64(req.Page * req.Limit)).SetLimit(int64(req.Limit))
|
||||
|
||||
var countChan = make(chan countResult)
|
||||
go func() {
|
||||
defer close(countChan)
|
||||
count, err := r.mdb.CountDocuments(ctx, filter)
|
||||
countChan <- countResult{count, err}
|
||||
}()
|
||||
|
||||
cursor, err := r.mdb.Find(ctx, filter, opt)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var promoCodes = make([]models.PromoCode, 0)
|
||||
for cursor.Next(ctx) {
|
||||
var p models.PromoCode
|
||||
if err := cursor.Decode(&p); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
promoCodes = append(promoCodes, p)
|
||||
}
|
||||
|
||||
if err := cursor.Err(); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := <-countChan
|
||||
if result.err != nil {
|
||||
return nil, 0, result.err
|
||||
}
|
||||
count := result.count
|
||||
|
||||
return promoCodes, count, nil
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ func (s *Server) registerRoutes() {
|
||||
|
||||
s.app.Post("/promocode/create", s.PromoCodeController.CreatePromoCode)
|
||||
s.app.Put("/promocode/edit", s.PromoCodeController.EditPromoCode)
|
||||
s.app.Post("/promocode/getList", s.PromoCodeController.GetList)
|
||||
//... other
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,9 @@ import (
|
||||
)
|
||||
|
||||
type PromoCodeRepository interface {
|
||||
CreatePromoCode(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error)
|
||||
EditPromoCode(ctx context.Context, reqEditPromoCode *models.ReqEditPromoCode) (*models.PromoCode, error)
|
||||
CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error)
|
||||
EditPromoCode(ctx context.Context, req *models.ReqEditPromoCode) (*models.PromoCode, error)
|
||||
GetPromoCodesList(ctx context.Context, req *models.GetPromoCodesListReq) ([]models.PromoCode, int64, error)
|
||||
}
|
||||
|
||||
type PromoDeps struct {
|
||||
@ -47,3 +48,13 @@ func (s *PromoCodeService) EditPromoCode(ctx context.Context, req *models.ReqEdi
|
||||
|
||||
return editedPromoCode, nil
|
||||
}
|
||||
|
||||
func (s *PromoCodeService) GetPromoCodesList(ctx context.Context, req *models.GetPromoCodesListReq) ([]models.PromoCode, int64, error) {
|
||||
promoCodes, count, err := s.promoCodeRepo.GetPromoCodesList(ctx, req)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get list promocodes from database", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return promoCodes, count, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user