This commit is contained in:
Pavel 2024-01-15 16:32:46 +03:00
parent e5c3b3786d
commit 33d0c25397
6 changed files with 98 additions and 29 deletions

@ -28,9 +28,11 @@ paths:
requestBody: requestBody:
required: true required: true
content: content:
application/x-www-form-urlencoded: application/json:
schema: schema:
type: object type: object
required:
- email
properties: properties:
email: email:
type: string type: string
@ -257,6 +259,60 @@ paths:
error: error:
type: string type: string
/promocode/fastlink:
post:
summary: Создать быструю ссылку для промокода
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
type: string
description: ID промокода, для которого нужно создать быструю ссылку
responses:
'201':
description: Быстрая ссылка для промокода успешно создана
content:
application/json:
schema:
type: object
properties:
fastlink:
type: string
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: components:
schemas: schemas:
@ -436,12 +492,13 @@ components:
ActivateReq: ActivateReq:
type: object type: object
required:
- codeword
properties: properties:
codeword: codeword:
type: string type: string
description: Кодовое слово промокода, которое требуется активировать description: Кодовое слово промокода, которое требуется активировать
fastLink:
type: string
description: Быстрая ссылка для активации промокода
ActivateResp: ActivateResp:
type: object type: object

@ -26,6 +26,12 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error {
cancel() cancel()
} }
if err = initialize.InitDatabaseIndexes(ctx, mdb, logger); err != nil {
logger.Error("Failed to initialize db indexes", zap.Error(err))
cancel()
return err
}
rdb, err := initialize.Redis(ctx, cfg) rdb, err := initialize.Redis(ctx, cfg)
encrypt := initialize.Encrypt(cfg) encrypt := initialize.Encrypt(cfg)

@ -135,9 +135,8 @@ func (p *PromoCodeController) Delete(c *fiber.Ctx) error {
// todo затестить и добавить в opnapi // todo затестить и добавить в opnapi
func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error { func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error {
// нужно что-то получать из Localstorage например id или codeword
var req struct { var req struct {
PromoCodeID string `json:"promoCodeID"` PromoCodeID string `json:"id"`
} }
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"}) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"})

@ -2,10 +2,8 @@ package recovery
import ( import (
"codeword/internal/models" "codeword/internal/models"
"codeword/internal/repository"
"codeword/internal/services" "codeword/internal/services"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"go.uber.org/zap" "go.uber.org/zap"
@ -57,14 +55,10 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
} }
user, err := r.service.FindUserByEmail(c.Context(), req.Email) user, err := r.service.FindUserByEmail(c.Context(), req.Email)
if err != nil { if err != nil || user == nil {
r.logger.Error("Failed to find user by email", zap.Error(err)) r.logger.Error("Failed to find user by email", zap.Error(err))
if errors.Is(err, repository.ErrPromoUserNotFound) { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
key, err := r.service.GenerateKey() key, err := r.service.GenerateKey()
@ -96,20 +90,16 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
} }
func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error {
var req models.RecoveryLinkRequest sign := c.Params("sign")
if err := c.BodyParser(&req); err != nil {
r.logger.Error("Failed to parse recovery link request", zap.Error(err))
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Bad Request"})
}
record, err := r.service.GetRecoveryRecord(c.Context(), req.Sign) record, err := r.service.GetRecoveryRecord(c.Context(), sign)
if err != nil { if err != nil {
r.logger.Error("Failed to get recovery record", zap.Error(err)) r.logger.Error("Failed to get recovery record", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
if time.Since(record.CreatedAt) > 15*time.Minute { if time.Since(record.CreatedAt) > 15*time.Minute {
r.logger.Error("Recovery link expired", zap.String("signature", req.Sign)) r.logger.Error("Recovery link expired", zap.String("signature", sign))
return c.Status(fiber.StatusNotAcceptable).JSON(fiber.Map{"error": "Recovery link expired"}) return c.Status(fiber.StatusNotAcceptable).JSON(fiber.Map{"error": "Recovery link expired"})
} }

@ -1,9 +1,11 @@
package initialize package initialize
import ( import (
"codeword/internal/repository"
mdb "codeword/pkg/mongo" mdb "codeword/pkg/mongo"
"context" "context"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
"time" "time"
) )
@ -17,7 +19,7 @@ func MongoDB(ctx context.Context, cfg Config) (*mongo.Database, error) {
MongoAuth: cfg.MongoAuth, MongoAuth: cfg.MongoAuth,
} }
ctx, cancel := context.WithTimeout(ctx, 10*time.Second) newCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel() defer cancel()
mongoDeps := &mdb.ConnectDeps{ mongoDeps := &mdb.ConnectDeps{
@ -25,15 +27,24 @@ func MongoDB(ctx context.Context, cfg Config) (*mongo.Database, error) {
Timeout: 10 * time.Second, Timeout: 10 * time.Second,
} }
db, err := mdb.Connect(ctx, mongoDeps) db, err := mdb.Connect(newCtx, mongoDeps)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = db.Client().Ping(ctx, nil) err = db.Client().Ping(newCtx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return db, nil return db, nil
} }
func InitDatabaseIndexes(ctx context.Context, mdb *mongo.Database, logger *zap.Logger) error {
if err := repository.InitPromoCodeIndexes(ctx, mdb.Collection("promoCodes")); err != nil {
logger.Error("Failed to initialize promoCodes indexes", zap.Error(err))
return err
}
return nil
}

@ -27,7 +27,10 @@ type PromoCodeRepository struct {
} }
func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository { func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository {
// todo заменить паники вроде как в роде не круто их юзать return &PromoCodeRepository{mdb: mdb}
}
func InitPromoCodeIndexes(ctx context.Context, mdb *mongo.Collection) error {
uniqueIndexModel := mongo.IndexModel{ uniqueIndexModel := mongo.IndexModel{
Keys: bson.D{ Keys: bson.D{
{Key: "codeword", Value: 1}, {Key: "codeword", Value: 1},
@ -35,9 +38,9 @@ func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository {
}, },
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"delete": false}), Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"delete": false}),
} }
_, err := mdb.Indexes().CreateOne(context.Background(), uniqueIndexModel) _, err := mdb.Indexes().CreateOne(ctx, uniqueIndexModel)
if err != nil { if err != nil {
panic(err) return err
} }
textIndexModel := mongo.IndexModel{ textIndexModel := mongo.IndexModel{
@ -48,17 +51,20 @@ func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository {
}, },
Options: options.Index().SetName("TextIndex"), Options: options.Index().SetName("TextIndex"),
} }
_, err = mdb.Indexes().CreateOne(context.Background(), textIndexModel) _, err = mdb.Indexes().CreateOne(ctx, textIndexModel)
if err != nil { if err != nil {
panic(err) return err
} }
return &PromoCodeRepository{mdb: mdb} return nil
} }
func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) { func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) {
req.CreatedAt = time.Now() req.CreatedAt = time.Now()
req.ID = primitive.NewObjectID() req.ID = primitive.NewObjectID()
if req.FastLinks == nil {
req.FastLinks = []string{}
}
_, err := r.mdb.InsertOne(ctx, req) _, err := r.mdb.InsertOne(ctx, req)
if err != nil { if err != nil {