Merge branch 'dev' into 'staging'

Мягкое удаление промокода и Черновик активации промокода

See merge request pena-services/codeword!12
This commit is contained in:
Mikhail 2024-02-29 17:40:59 +00:00
commit 05a6f48d45
6 changed files with 227 additions and 1 deletions

@ -193,6 +193,70 @@ paths:
'500':
description: Внутренняя ошибка сервера
/promocode/activate:
post:
summary: Активировать промокод
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ActivateReq'
responses:
'200':
description: Промокод успешно активирован
content:
application/json:
schema:
$ref: '#/components/schemas/ActivateResp'
'400':
description: Невалидный запрос или отсутствует обязательное поле codeword
'404':
description: Промокод не найден
'500':
description: Внутренняя ошибка сервера
/promocode/{promocodeID}:
delete:
summary: Мягко удалить промокод по его id
parameters:
- in: path
name: promocodeID
required: true
schema:
type: string
description: Id промокода для удаления
responses:
'204':
description: Промокод успешно помечен как удаленный
'400':
description: Неверный запрос, отсутствует идентификатор промокода
content:
application/json:
schema:
type: object
properties:
error:
type: string
'404':
description: Промокод не найден
content:
application/json:
schema:
type: object
properties:
error:
type: string
'500':
description: Внутренняя ошибка сервера
content:
application/json:
schema:
type: object
properties:
error:
type: string
components:
schemas:
@ -386,4 +450,20 @@ components:
items:
type: array
items:
$ref: '#/components/schemas/PromoCodeResponse'
$ref: '#/components/schemas/PromoCodeResponse'
ActivateReq:
type: object
required:
- codeword
properties:
codeword:
type: string
description: Кодовое слово промокода, которое требуется активировать
ActivateResp:
type: object
properties:
greetings:
type: string
description: Поле из активированного промокода

@ -82,3 +82,51 @@ func (p *PromoCodeController) GetList(c *fiber.Ctx) error {
Items: promoCodes,
})
}
func (p *PromoCodeController) Activate(c *fiber.Ctx) error {
var req models.ActivateReq
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"})
}
if req.Codeword == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "codeword is required"})
}
greetings, err := p.promoCodeService.ActivatePromo(c.Context(), &req)
if err != nil {
p.logger.Error("Failed to activate promocode", zap.Error(err))
if errors.Is(err, repository.ErrPromoCodeNotFound) {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "PromoCode not found"})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
resp := models.ActivateResp{
Greetings: greetings,
}
return c.Status(fiber.StatusOK).JSON(resp)
}
func (p *PromoCodeController) Delete(c *fiber.Ctx) error {
promoCodeID := c.Params("promocodeID")
if promoCodeID == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode ID is required"})
}
err := p.promoCodeService.DeletePromoCode(c.Context(), promoCodeID)
if err != nil {
p.logger.Error("Failed to delete promocode", zap.Error(err))
if errors.Is(err, repository.ErrPromoCodeNotFound) {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "PromoCode not found"})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
return c.SendStatus(fiber.StatusOK)
}

@ -70,3 +70,11 @@ type GetPromoCodesListResp struct {
Count int64 `json:"count"` // количество в выборке всего
Items []PromoCode `json:"items"` // "страница" промокодов
}
type ActivateReq struct {
Codeword string `json:"codeword"`
}
type ActivateResp struct {
Greetings string `json:"greetings"` // поле из активированного промокода
}

@ -213,3 +213,69 @@ func (r *PromoCodeRepository) GetPromoCodesList(ctx context.Context, req *models
return promoCodes, count, nil
}
func (r *PromoCodeRepository) ActivatePromo(ctx context.Context, req *models.ActivateReq) (string, error) {
session, err := r.mdb.Database().Client().StartSession()
if err != nil {
return "", err
}
defer session.EndSession(ctx)
var greetings string
transactionErr := mongo.WithSession(ctx, session, func(sc mongo.SessionContext) error {
filter := bson.M{
"codeword": req.Codeword,
"delete": false,
"outdated": false,
"offLimit": false,
"activationCount": bson.M{"$gt": 0},
"dueTo": bson.M{"$gt": time.Now().Unix()},
}
update := bson.M{
"$inc": bson.M{"activationCount": -1},
}
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
var updatedPromoCode models.PromoCode
err := r.mdb.FindOneAndUpdate(sc, filter, update, opts).Decode(&updatedPromoCode)
if err != nil {
if err == mongo.ErrNoDocuments {
return ErrPromoCodeNotFound
}
return err
}
greetings = updatedPromoCode.Greetings
return nil
})
if transactionErr != nil {
return "", transactionErr
}
return greetings, nil
}
func (r *PromoCodeRepository) DeletePromoCode(ctx context.Context, promoCodeID string) error {
id, err := primitive.ObjectIDFromHex(promoCodeID)
if err != nil {
return err
}
result, err := r.mdb.UpdateOne(
ctx,
bson.M{"_id": id, "delete": false},
bson.M{"$set": bson.M{"delete": true}},
)
if err != nil {
return err
}
if result.MatchedCount == 0 {
return ErrPromoCodeNotFound
}
return nil
}

@ -60,6 +60,8 @@ 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)
s.app.Post("/promocode/activate", s.PromoCodeController.Activate)
s.app.Delete("/promocode/:promocodeID", s.PromoCodeController.Delete)
//... other
}

@ -10,6 +10,8 @@ type PromoCodeRepository interface {
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)
ActivatePromo(ctx context.Context, req *models.ActivateReq) (string, error)
DeletePromoCode(ctx context.Context, promoCodeID string) error
}
type PromoDeps struct {
@ -58,3 +60,23 @@ func (s *PromoCodeService) GetPromoCodesList(ctx context.Context, req *models.Ge
return promoCodes, count, nil
}
func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.ActivateReq) (string, error) {
greetings, err := s.promoCodeRepo.ActivatePromo(ctx, req)
if err != nil {
s.logger.Error("Failed to activate promocode", zap.Error(err))
return "", err
}
return greetings, nil
}
func (s *PromoCodeService) DeletePromoCode(ctx context.Context, promoCodeID string) error {
err := s.promoCodeRepo.DeletePromoCode(ctx, promoCodeID)
if err != nil {
s.logger.Error("Failed simple delete promocode from database", zap.Error(err))
return err
}
return nil
}