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 }