tools/transfer_to_clickhouse/transfer/codeword.go
2025-02-14 18:08:50 +03:00

232 lines
7.3 KiB
Go

package transfer
import (
"context"
"errors"
"fmt"
"gitea.pena/PenaSide/hlog"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"time"
"transfer_to_clickhouse/models"
)
const promoCodesColl = "promoCodes"
const promoStatsColl = "promoStats"
type Codeword struct {
logger hlog.Logger
collectionPromoCodes *mongo.Collection
collectionPromoStats *mongo.Collection
}
func NewCodeword(logger hlog.Logger, db *mongo.Database) *Codeword {
return &Codeword{
logger: logger,
collectionPromoCodes: db.Collection(promoCodesColl),
collectionPromoStats: db.Collection(promoStatsColl),
}
}
type PromoCodeStats struct {
ID primitive.ObjectID `bson:"_id" json:"id,omitempty"`
UsageMap map[string][]struct {
UserID string `bson:"userID" json:"userID"`
Time uint64 `bson:"time" json:"time"`
} `bson:"usageMap" json:"usageMap"`
}
type PromoCode struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
Codeword string `json:"codeword" bson:"codeword"` // то, что будет вводить пользователь, чтобы получить плюшки
Description string `json:"description" bson:"description"` // описание, необходимое менеджеру в админке
Greetings string `json:"greetings" bson:"greetings"` // текст, выдаваемый пользователю в ответ на активацию промокода
DueTo int64 `json:"dueTo" bson:"dueTo"` // таймштамп времени окончания работы активации промокода
ActivationCount int64 `json:"activationCount" bson:"activationCount"` // предел количества активаций промокода
ActivationLimit int64 `json:"activationLimit" bson:"activationLimit"` // лимит если 0 то без лимита
Bonus struct {
Privilege struct {
PrivilegeID string `json:"privilegeID" bson:"privilegeID"` // айдишник привилегии, которая будет выдаваться
Amount uint64 `json:"amount" bson:"amount"` // количество
ServiceKey string `json:"serviceKey" bson:"serviceKey"` // тип сервиса
} `json:"privilege" bson:"privilege"`
Discount struct {
Layer uint32 `json:"layer" bson:"layer"` // 1|2
Factor float64 `json:"factor" bson:"factor"` // процент скидки, вернее множитель, при котором достигается этот процент скидки
Target string `json:"target" bson:"target"` // PrivilegeID или ServiceKey в зависимости от слоя
Threshold int64 `json:"threshold" bson:"threshold"` // граничное значение, при пересечении которого применяется эта скидка
} `json:"discount" bson:"discount"`
} `json:"bonus" bson:"bonus"`
Outdated bool `json:"outdated" bson:"outdated"`
OffLimit bool `json:"offLimit" bson:"offLimit"`
Delete bool `json:"delete" bson:"delete"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
FastLinks []string `json:"fastLinks" bson:"fastLinks"`
}
func (r *Codeword) ActivatedEvents(ctx context.Context) error {
var promoCodeStatsList []PromoCodeStats
filter := bson.M{}
cursor, err := r.collectionPromoStats.Find(ctx, filter)
if err != nil {
return err
}
defer cursor.Close(ctx)
for cursor.Next(ctx) {
var promoCodeStats PromoCodeStats
if err := cursor.Decode(&promoCodeStats); err != nil {
continue
}
promoCodeStatsList = append(promoCodeStatsList, promoCodeStats)
}
if err := cursor.Err(); err != nil {
return err
}
for _, i := range promoCodeStatsList {
promoCode, err := r.GetPromoCode(ctx, i.ID)
if err != nil {
fmt.Println(err)
continue
}
for key, u := range i.UsageMap {
if key == promoCode.Codeword {
for _, j := range u {
r.logger.Emit(models.InfoPromocodeActivated{
CtxID: i.ID.String(),
CtxUserID: j.UserID,
CtxCode: key,
})
}
} else {
for _, j := range u {
r.logger.Emit(models.InfoFastlinkActivated{
CtxID: i.ID.String(),
CtxUserID: j.UserID,
CtxPromocodeID: key,
})
}
}
}
}
return nil
}
func (r *Codeword) GetPromoCode(ctx context.Context, promoCodeID primitive.ObjectID) (*PromoCode, error) {
filter := bson.M{"_id": promoCodeID}
var promoCode PromoCode
err := r.collectionPromoCodes.FindOne(ctx, filter).Decode(&promoCode)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return nil, err
}
return nil, err
}
return &promoCode, nil
}
func (r *Codeword) DeletedEvents(ctx context.Context) error {
filter := bson.M{"delete": true}
var deletedPromoCodes []PromoCode
cursor, err := r.collectionPromoCodes.Find(ctx, filter)
if err != nil {
return err
}
defer cursor.Close(ctx)
for cursor.Next(ctx) {
var promoCode PromoCode
if err := cursor.Decode(&promoCode); err != nil {
return err
}
deletedPromoCodes = append(deletedPromoCodes, promoCode)
}
if err := cursor.Err(); err != nil {
return err
}
for _, i := range deletedPromoCodes {
r.logger.Emit(models.InfoPromocodeDeleted{
CtxID: i.ID.String(),
})
}
return nil
}
func (r *Codeword) EventCreate(ctx context.Context) error {
filter := bson.M{}
var promoCodes []PromoCode
cursor, err := r.collectionPromoCodes.Find(ctx, filter)
if err != nil {
return err
}
defer cursor.Close(ctx)
for cursor.Next(ctx) {
var promoCode PromoCode
if err := cursor.Decode(&promoCode); err != nil {
return err
}
promoCodes = append(promoCodes, promoCode)
}
if err := cursor.Err(); err != nil {
return err
}
for _, createdPromoCode := range promoCodes {
var keyType string
var keyTargetType string
var ctxTarget string
var ctxAmount int64
if createdPromoCode.Bonus.Privilege.PrivilegeID != "" && createdPromoCode.Bonus.Discount.Factor != 0 && createdPromoCode.Bonus.Discount.Factor != 1 {
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)
} 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 && createdPromoCode.Bonus.Discount.Factor != 1 {
keyType = "discount"
keyTargetType = "service"
ctxTarget = createdPromoCode.Bonus.Discount.Target
}
r.logger.Emit(models.InfoPromocodeCreated{
CtxID: createdPromoCode.ID.String(),
KeyType: keyType,
KeyTargetType: keyTargetType,
CtxTarget: ctxTarget,
CtxAmount: ctxAmount,
CtxCode: createdPromoCode.Codeword,
})
if len(createdPromoCode.FastLinks) > 0 {
for _, link := range createdPromoCode.FastLinks {
r.logger.Emit(models.InfoFastlinkCreated{
CtxID: link,
CtxPromocodeID: createdPromoCode.ID.String(),
})
}
}
}
return nil
}