add logging events

This commit is contained in:
Pavel 2024-05-28 14:05:31 +03:00
parent 9ee582a12e
commit 201b8b4207
9 changed files with 250 additions and 63 deletions

@ -10,10 +10,10 @@ import (
"codeword/internal/server/grpc" "codeword/internal/server/grpc"
httpserver "codeword/internal/server/http" httpserver "codeword/internal/server/http"
"codeword/internal/services" "codeword/internal/services"
"codeword/internal/utils/middleware"
"codeword/internal/worker/purge_worker" "codeword/internal/worker/purge_worker"
"codeword/internal/worker/recovery_worker" "codeword/internal/worker/recovery_worker"
"codeword/pkg/closer" "codeword/pkg/closer"
"codeword/utils"
"context" "context"
"errors" "errors"
"github.com/themakers/hlog" "github.com/themakers/hlog"
@ -126,11 +126,15 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger, build B
DiscountClient: discountRpcClient, DiscountClient: discountRpcClient,
}) })
jwtUtil := utils.NewJWT(&cfg) jwtUtil := middleware.NewJWT(&cfg)
authMiddleware := utils.NewAuthenticator(jwtUtil)
recoveryController := recovery.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL) recoveryController := recovery.NewRecoveryController(recovery.Deps{
promoCodeController := promocode.NewPromoCodeController(promocode.Deps{Logger: logger, PromoCodeService: promoService, AuthMiddleware: authMiddleware}) Logger: logger,
Service: recoveryService,
DefaultURL: cfg.DefaultRedirectionURL,
RecoveryURL: cfg.RecoveryUrl,
})
promoCodeController := promocode.NewPromoCodeController(promocode.Deps{Logger: logger, PromoCodeService: promoService})
controllerRpc := rpc_controllers.InitRpcControllers(promoService) controllerRpc := rpc_controllers.InitRpcControllers(promoService)
grpcServer, err := grpc.NewGRPC(logger) grpcServer, err := grpc.NewGRPC(logger)
@ -159,6 +163,7 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger, build B
Logger: logger, Logger: logger,
Controllers: []httpserver.Controller{recoveryController, promoCodeController}, Controllers: []httpserver.Controller{recoveryController, promoCodeController},
Hlogger: loggerHlog, Hlogger: loggerHlog,
JWT: jwtUtil,
}) })
go func() { go func() {

@ -4,33 +4,34 @@ import (
"codeword/internal/models" "codeword/internal/models"
"codeword/internal/repository" "codeword/internal/repository"
"codeword/internal/services" "codeword/internal/services"
"codeword/internal/utils/middleware"
"errors" "errors"
"fmt" "fmt"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"go.uber.org/zap" "go.uber.org/zap"
"strings"
) )
type Deps struct { type Deps struct {
Logger *zap.Logger Logger *zap.Logger
PromoCodeService *services.PromoCodeService PromoCodeService *services.PromoCodeService
AuthMiddleware func(*fiber.Ctx) error
} }
type PromoCodeController struct { type PromoCodeController struct {
logger *zap.Logger logger *zap.Logger
promoCodeService *services.PromoCodeService promoCodeService *services.PromoCodeService
authMiddleware func(*fiber.Ctx) error
} }
func NewPromoCodeController(deps Deps) *PromoCodeController { func NewPromoCodeController(deps Deps) *PromoCodeController {
return &PromoCodeController{ return &PromoCodeController{
logger: deps.Logger, logger: deps.Logger,
promoCodeService: deps.PromoCodeService, promoCodeService: deps.PromoCodeService,
authMiddleware: deps.AuthMiddleware,
} }
} }
func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error { func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error {
userID := middleware.ExtractUserID(c)
hlogger := middleware.ExtractLogger(c)
var req models.PromoCode var req models.PromoCode
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"})
@ -53,10 +54,52 @@ func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
var keyType string
var ctxFactor float64
var keyTargetType string
var ctxTarget string
var ctxAmount int64
if createdPromoCode.Bonus.Privilege.PrivilegeID != "" && createdPromoCode.Bonus.Discount.Layer > 0 {
keyType = "privilege,discount"
keyTargetType = "privilege,service"
ctxTarget = fmt.Sprintf("%s,%s", createdPromoCode.Bonus.Privilege.PrivilegeID, createdPromoCode.Bonus.Discount.Target)
ctxAmount = int64(createdPromoCode.Bonus.Privilege.Amount)
ctxFactor = createdPromoCode.Bonus.Discount.Factor
} else if createdPromoCode.Bonus.Privilege.PrivilegeID != "" {
keyType = "privilege"
keyTargetType = "privilege"
ctxTarget = createdPromoCode.Bonus.Privilege.PrivilegeID
ctxAmount = int64(createdPromoCode.Bonus.Privilege.Amount)
} else if createdPromoCode.Bonus.Discount.Factor > 0 {
keyType = "discount"
keyTargetType = "service"
ctxFactor = createdPromoCode.Bonus.Discount.Factor
ctxTarget = createdPromoCode.Bonus.Discount.Target
}
hlogger.Emit(models.InfoPromocodeCreated{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: createdPromoCode.ID.String(),
CtxUserID: userID,
KeyType: keyType,
CtxFactor: ctxFactor,
KeyTargetType: keyTargetType,
CtxTarget: ctxTarget,
CtxAmount: ctxAmount,
CtxCode: createdPromoCode.Codeword,
})
return c.Status(fiber.StatusOK).JSON(createdPromoCode) return c.Status(fiber.StatusOK).JSON(createdPromoCode)
} }
func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error { func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error {
userID := middleware.ExtractUserID(c)
hlogger := middleware.ExtractLogger(c)
var req models.ReqEditPromoCode var req models.ReqEditPromoCode
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"})
@ -79,6 +122,45 @@ func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
var keyType string
var ctxFactor float64
var keyTargetType string
var ctxTarget string
var ctxAmount int64
if editedPromoCode.Bonus.Privilege.PrivilegeID != "" && editedPromoCode.Bonus.Discount.Layer > 0 {
keyType = "privilege,discount"
keyTargetType = "privilege,service"
ctxTarget = fmt.Sprintf("%s,%s", editedPromoCode.Bonus.Privilege.PrivilegeID, editedPromoCode.Bonus.Discount.Target)
ctxAmount = int64(editedPromoCode.Bonus.Privilege.Amount)
ctxFactor = editedPromoCode.Bonus.Discount.Factor
} else if editedPromoCode.Bonus.Privilege.PrivilegeID != "" {
keyType = "privilege"
keyTargetType = "privilege"
ctxTarget = editedPromoCode.Bonus.Privilege.PrivilegeID
ctxAmount = int64(editedPromoCode.Bonus.Privilege.Amount)
} else if editedPromoCode.Bonus.Discount.Factor > 0 {
keyType = "discount"
keyTargetType = "service"
ctxFactor = editedPromoCode.Bonus.Discount.Factor
ctxTarget = editedPromoCode.Bonus.Discount.Target
}
hlogger.Emit(models.InfoPromocodeUpdated{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: editedPromoCode.ID.String(),
CtxUserID: userID,
KeyType: keyType,
CtxFactor: ctxFactor,
KeyTargetType: keyTargetType,
CtxTarget: ctxTarget,
CtxAmount: ctxAmount,
CtxCode: editedPromoCode.Codeword,
})
return c.Status(fiber.StatusOK).JSON(editedPromoCode) return c.Status(fiber.StatusOK).JSON(editedPromoCode)
} }
@ -101,13 +183,8 @@ func (p *PromoCodeController) GetList(c *fiber.Ctx) error {
} }
func (p *PromoCodeController) Activate(c *fiber.Ctx) error { func (p *PromoCodeController) Activate(c *fiber.Ctx) error {
err := p.authMiddleware(c) userID := middleware.ExtractUserID(c)
fmt.Println("SKER0", err) hlogger := middleware.ExtractLogger(c)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err})
}
userID := c.Locals(models.AuthJWTDecodedUserIDKey).(string)
fmt.Println("SKER1", userID) fmt.Println("SKER1", userID)
if userID == "" { if userID == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "failed to get jwt payload"}) return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "failed to get jwt payload"})
@ -123,7 +200,7 @@ func (p *PromoCodeController) Activate(c *fiber.Ctx) error {
} }
fmt.Println("SKER2", req) fmt.Println("SKER2", req)
greetings, err := p.promoCodeService.ActivatePromo(c.Context(), &req, userID) promocode, err := p.promoCodeService.ActivatePromo(c.Context(), &req, userID)
fmt.Println("SKER3", err) fmt.Println("SKER3", err)
if err != nil { if err != nil {
p.logger.Error("Failed to activate promocode", zap.Error(err)) p.logger.Error("Failed to activate promocode", zap.Error(err))
@ -134,20 +211,58 @@ func (p *PromoCodeController) Activate(c *fiber.Ctx) error {
case errors.Is(err, repository.ErrPromoCodeAlreadyActivated): case errors.Is(err, repository.ErrPromoCodeAlreadyActivated):
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "PromoCode already activated"}) return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "PromoCode already activated"})
case errors.Is(err, repository.ErrPromoCodeExpired): case errors.Is(err, repository.ErrPromoCodeExpired):
hlogger.Emit(models.InfoPromocodeDeadlined{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: promocode.ID.String(),
})
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
case errors.Is(err, repository.ErrPromoCodeExhausted): case errors.Is(err, repository.ErrPromoCodeExhausted):
hlogger.Emit(models.InfoPromocodeExhausted{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: promocode.ID.String(),
})
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode exhausted"}) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode exhausted"})
default: default:
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
} }
return c.Status(fiber.StatusOK).JSON(models.ActivateResp{Greetings: greetings}) if req.Codeword != "" {
hlogger.Emit(models.InfoPromocodeActivated{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: promocode.ID.String(),
CtxUserID: userID,
CtxCode: req.Codeword,
})
} else if req.FastLink != "" {
hlogger.Emit(models.InfoFastlinkActivated{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: promocode.ID.String(),
CtxUserID: userID,
CtxPromocodeID: req.FastLink,
})
}
return c.Status(fiber.StatusOK).JSON(models.ActivateResp{Greetings: promocode.Greetings})
} }
func (p *PromoCodeController) Delete(c *fiber.Ctx) error { func (p *PromoCodeController) Delete(c *fiber.Ctx) error {
promoCodeID := c.Params("promocodeID") userID := middleware.ExtractUserID(c)
hlogger := middleware.ExtractLogger(c)
promoCodeID := c.Params("promocodeID")
if promoCodeID == "" { if promoCodeID == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode ID is required"}) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode ID is required"})
} }
@ -163,10 +278,22 @@ func (p *PromoCodeController) Delete(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
hlogger.Emit(models.InfoPromocodeDeleted{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: promoCodeID,
CtxUserID: userID,
})
return c.SendStatus(fiber.StatusOK) return c.SendStatus(fiber.StatusOK)
} }
func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error { func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error {
userID := middleware.ExtractUserID(c)
hlogger := middleware.ExtractLogger(c)
var req struct { var req struct {
PromoCodeID string `json:"id"` PromoCodeID string `json:"id"`
} }
@ -189,6 +316,16 @@ func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
hlogger.Emit(models.InfoFastlinkCreated{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: fastLink,
CtxPromocodeID: req.PromoCodeID,
CtxUserID: userID,
})
return c.Status(fiber.StatusCreated).JSON(fiber.Map{"fastlink": fastLink}) return c.Status(fiber.StatusCreated).JSON(fiber.Map{"fastlink": fastLink})
} }

@ -4,25 +4,36 @@ import (
"codeword/internal/models" "codeword/internal/models"
"codeword/internal/repository" "codeword/internal/repository"
"codeword/internal/services" "codeword/internal/services"
"codeword/internal/utils/middleware"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"go.uber.org/zap" "go.uber.org/zap"
"strings"
"time" "time"
) )
type RecoveryController struct { type Deps struct {
logger *zap.Logger Logger *zap.Logger
service *services.RecoveryService Service *services.RecoveryService
defaultURL string DefaultURL string
RecoveryURL string
} }
func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService, defaultRedirectionURL string) *RecoveryController { type RecoveryController struct {
logger *zap.Logger
service *services.RecoveryService
defaultURL string
recoveryURL string
}
func NewRecoveryController(deps Deps) *RecoveryController {
return &RecoveryController{ return &RecoveryController{
logger: logger, logger: deps.Logger,
service: service, service: deps.Service,
defaultURL: defaultRedirectionURL, defaultURL: deps.DefaultURL,
recoveryURL: deps.RecoveryURL,
} }
} }
@ -45,6 +56,7 @@ func (r *RecoveryController) HandlePingDB(c *fiber.Ctx) error {
} }
func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error { func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
hlogger := middleware.ExtractLogger(c)
var req models.RecoveryRequest var req models.RecoveryRequest
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
r.logger.Error("Failed to parse recovery request", zap.Error(err)) r.logger.Error("Failed to parse recovery request", zap.Error(err))
@ -79,11 +91,11 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
sign := base64.URLEncoding.EncodeToString(key) sign := base64.URLEncoding.EncodeToString(key)
id, err := r.service.StoreRecoveryRecord(c.Context(), models.StoreRecDeps{ id, err := r.service.StoreRecoveryRecord(c.Context(), models.StoreRecDeps{
UserID: user.ID.Hex(), UserID: user.ID.Hex(),
Email: user.Email, Email: user.Email,
Key: sign, Key: sign,
Url: signUrl, Url: signUrl,
}) })
if err != nil { if err != nil {
r.logger.Error("Failed to store recovery record", zap.Error(err)) r.logger.Error("Failed to store 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"})
@ -102,36 +114,48 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
} }
hlogger.Emit(models.InfoPasswordRestorationRequested{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: id,
CtxUserID: user.ID.Hex(),
CtxReturnURL: r.recoveryURL + signWithID,
CtxEmail: req.Email,
})
return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Recovery email sent successfully"}) return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Recovery email sent successfully"})
} }
func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error {
hlogger := middleware.ExtractLogger(c)
sign := c.Params("sign") sign := c.Params("sign")
record, err := r.service.GetRecoveryRecord(c.Context(), sign) record, err := r.service.GetRecoveryRecord(c.Context(), sign)
if err != nil { if err != nil {
r.logger.Error("Recovery link expired", zap.String("signature", sign)) r.logger.Error("Recovery link expired", zap.String("signature", sign))
return c.Redirect("https://shub.pena.digital/recover/expired") return c.Redirect("https://shub.pena.digital/recover/expired")
} }
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", sign)) r.logger.Error("Recovery link expired", zap.String("signature", sign))
return c.Redirect(record.SignUrl+"/expired") return c.Redirect(record.SignUrl + "/expired")
} }
tokens, err := r.service.ExchangeForTokens(record.UserID, record.Sign) tokens, err := r.service.ExchangeForTokens(record.UserID, record.Sign)
if err != nil { if err != nil {
r.logger.Error("Failed to exchange recovery link for tokens", zap.Error(err)) r.logger.Error("Failed to exchange recovery link for tokens", 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"})
} }
c.Cookie(&fiber.Cookie{ c.Cookie(&fiber.Cookie{
Name: "refreshToken", Name: "refreshToken",
Value: tokens["refreshToken"], Value: tokens["refreshToken"],
Domain: ".pena.digital", Domain: ".pena.digital",
Expires: time.Now().Add(30 * 24 * time.Hour), Expires: time.Now().Add(30 * 24 * time.Hour),
Secure: true, Secure: true,
HTTPOnly: true, HTTPOnly: true,
}) })
c.Cookie(&fiber.Cookie{ c.Cookie(&fiber.Cookie{
Name: "refreshToken", Name: "refreshToken",
@ -142,5 +166,14 @@ func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error {
HTTPOnly: true, HTTPOnly: true,
}) })
hlogger.Emit(models.InfoPasswordRestored{
CtxUserIP: c.IP(),
CtxUserPort: c.Port(),
KeyDomain: strings.Join(c.Subdomains(), "/"),
KeyPath: c.Path(),
CtxID: record.ID.String(),
CtxUserID: record.UserID,
})
return c.Redirect(record.SignUrl + "?auth=" + tokens["accessToken"]) return c.Redirect(record.SignUrl + "?auth=" + tokens["accessToken"])
} }

@ -1,7 +1,7 @@
package http package http
import ( import (
"codeword/internal/utils/hlogger_mw" "codeword/internal/utils/middleware"
"context" "context"
"fmt" "fmt"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
@ -13,6 +13,7 @@ type ServerConfig struct {
Logger *zap.Logger Logger *zap.Logger
Controllers []Controller Controllers []Controller
Hlogger hlog.Logger Hlogger hlog.Logger
JWT *middleware.JWT
} }
type Server struct { type Server struct {
@ -23,7 +24,8 @@ type Server struct {
func NewServer(config ServerConfig) *Server { func NewServer(config ServerConfig) *Server {
app := fiber.New() app := fiber.New()
app.Use(hlogger_mw.ContextLogger(config.Hlogger)) app.Use(middleware.ContextLogger(config.Hlogger))
app.Use("/promocode", middleware.NewAuthenticator(config.JWT))
s := &Server{ s := &Server{
Logger: config.Logger, Logger: config.Logger,
Controllers: config.Controllers, Controllers: config.Controllers,

@ -93,30 +93,30 @@ func (s *PromoCodeService) GetPromoCodesList(ctx context.Context, req *models.Ge
// разделяется ли она или они всегда вместе, если разделяются то что-то из этого может быть пустым либо все заполеннное, // разделяется ли она или они всегда вместе, если разделяются то что-то из этого может быть пустым либо все заполеннное,
// соответсвенно надо сделать соответствующие проверки до записи в кафку и до отправки в дискаунт сервис // соответсвенно надо сделать соответствующие проверки до записи в кафку и до отправки в дискаунт сервис
func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.ActivateReq, userID string) (string, error) { func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.ActivateReq, userID string) (*models.PromoCode, error) {
promoCode, err := s.promoCodeRepo.ActivatePromo(ctx, req) promoCode, err := s.promoCodeRepo.ActivatePromo(ctx, req)
fmt.Println("SKER20", err, promoCode, time.Now().Unix()) fmt.Println("SKER20", err, promoCode, time.Now().Unix())
if err != nil { if err != nil {
s.logger.Error("Failed to activate promocode", zap.Error(err)) s.logger.Error("Failed to activate promocode", zap.Error(err))
return "", err return nil, err
} }
//todo такая реализация проверок кажется довольно массивной, думаю как то это стоит сделать параллельно обхаживая все условия //todo такая реализация проверок кажется довольно массивной, думаю как то это стоит сделать параллельно обхаживая все условия
if promoCode.DueTo < time.Now().Unix() && promoCode.DueTo > 0 { if promoCode.DueTo < time.Now().Unix() && promoCode.DueTo > 0 {
err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID) err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID)
fmt.Println("SKER21", err) fmt.Println("SKER21", err)
if err != nil { if err != nil {
return "", err return nil, err
} }
return "", fmt.Errorf("%w: expired on %s", repository.ErrPromoCodeExpired, time.Unix(promoCode.DueTo, 0).Format(time.RFC3339)) return nil, fmt.Errorf("%w: expired on %s", repository.ErrPromoCodeExpired, time.Unix(promoCode.DueTo, 0).Format(time.RFC3339))
} }
if promoCode.DueTo == 0 && promoCode.ActivationCount < 0 && promoCode.ActivationLimit != 0 { if promoCode.DueTo == 0 && promoCode.ActivationCount < 0 && promoCode.ActivationLimit != 0 {
err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID) err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID)
fmt.Println("SKER22", err) fmt.Println("SKER22", err)
if err != nil { if err != nil {
return "", err return nil, err
} }
return "", repository.ErrPromoCodeExhausted return nil, repository.ErrPromoCodeExhausted
} }
err = s.statsRepo.UpdateStatistics(ctx, req, promoCode, userID) err = s.statsRepo.UpdateStatistics(ctx, req, promoCode, userID)
@ -125,12 +125,12 @@ func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.Activa
if errors.Is(err, repository.ErrPromoCodeAlreadyActivated) { if errors.Is(err, repository.ErrPromoCodeAlreadyActivated) {
err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID) err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID)
if err != nil { if err != nil {
return "", err return nil, err
} }
return "", repository.ErrPromoCodeAlreadyActivated return nil, repository.ErrPromoCodeAlreadyActivated
} }
s.logger.Error("Failed add in stats", zap.Error(err)) s.logger.Error("Failed add in stats", zap.Error(err))
return "", err return nil, err
} }
var postfix string var postfix string
@ -158,7 +158,7 @@ func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.Activa
fmt.Println("SKER24", err) fmt.Println("SKER24", err)
if err := s.kafka.Send(ctx, userID, fakeTariff); err != nil { if err := s.kafka.Send(ctx, userID, fakeTariff); err != nil {
s.logger.Error("Failed to send fake tariff to Kafka", zap.Error(err)) s.logger.Error("Failed to send fake tariff to Kafka", zap.Error(err))
return "", err return nil, err
} }
} }
@ -205,11 +205,11 @@ func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.Activa
_, err = s.discountClient.CreateDiscount(ctx, discountRequest) _, err = s.discountClient.CreateDiscount(ctx, discountRequest)
if err != nil { if err != nil {
s.logger.Error("Failed to create discount", zap.Error(err)) s.logger.Error("Failed to create discount", zap.Error(err))
return "", err return nil, err
} }
} }
return promoCode.Greetings, nil return promoCode, nil
} }
func (s *PromoCodeService) DeletePromoCode(ctx context.Context, promoCodeID string) error { func (s *PromoCodeService) DeletePromoCode(ctx context.Context, promoCodeID string) error {

@ -1,9 +1,9 @@
package utils package middleware
import ( import (
"codeword/internal/models" "codeword/internal/models"
"strings"
"fmt" "fmt"
"strings"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
@ -44,3 +44,8 @@ func authenticate(c *fiber.Ctx, jwtUtil *JWT) error {
return nil return nil
} }
func ExtractUserID(c *fiber.Ctx) string {
userID := c.Context().UserValue(models.AuthJWTDecodedUserIDKey).(string)
return userID
}

@ -1,4 +1,4 @@
package utils package middleware
import ( import (
"codeword/internal/initialize" "codeword/internal/initialize"

@ -1,4 +1,4 @@
package hlogger_mw package middleware
import ( import (
"codeword/internal/models" "codeword/internal/models"
@ -12,3 +12,8 @@ func ContextLogger(logger hlog.Logger) fiber.Handler {
return c.Next() return c.Next()
} }
} }
func ExtractLogger(c *fiber.Ctx) hlog.Logger {
logger := c.Context().UserValue(models.LoggerKey).(hlog.Logger)
return logger
}

@ -2,11 +2,11 @@ package helpers
import ( import (
"codeword/internal/initialize" "codeword/internal/initialize"
"codeword/utils" "codeword/internal/utils/middleware"
"strings" "strings"
) )
func InitializeJWT() *utils.JWT { func InitializeJWT() *middleware.JWT {
publicKey := strings.Replace(`-----BEGIN PUBLIC KEY----- publicKey := strings.Replace(`-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69 MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69
80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B 80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B
@ -29,7 +29,7 @@ func InitializeJWT() *utils.JWT {
7McQvEk12dU/JNTX8wJAOlAtSNjp9tVwpMpC0w2St1eKc1L2SknjeohA5ldoBz8sGeZsPhTU3eHSD1neAZXLKN5K68z3zFBr20ubY9nyLw== 7McQvEk12dU/JNTX8wJAOlAtSNjp9tVwpMpC0w2St1eKc1L2SknjeohA5ldoBz8sGeZsPhTU3eHSD1neAZXLKN5K68z3zFBr20ubY9nyLw==
-----END RSA PRIVATE KEY-----`, "\t", "", -1) -----END RSA PRIVATE KEY-----`, "\t", "", -1)
return utils.NewJWT(&initialize.Config{ return middleware.NewJWT(&initialize.Config{
PrivateKey: privateKey, PrivateKey: privateKey,
PublicKey: publicKey, PublicKey: publicKey,
Audience: "pena", Audience: "pena",