diff --git a/api/consts/consts.go b/api/consts/consts.go index 99242fbe..fa27f2d0 100644 --- a/api/consts/consts.go +++ b/api/consts/consts.go @@ -41,6 +41,7 @@ const ( ImageIdForUploadFail = "image_id_for_upload_fail" VideoIdForUploadFail = "video_id_for_upload_fail" RestrictedVisitorKey = "restricted_visitor" + MaxDailyMomentCreateTimesKey = "max_daily_moment_create_times" ) // del_flag diff --git a/api/errcode/errcode.go b/api/errcode/errcode.go index 89a8eb6e..5dd0d4d9 100644 --- a/api/errcode/errcode.go +++ b/api/errcode/errcode.go @@ -143,6 +143,10 @@ var ErrCodeMsgMap = map[ErrCode]string{ ErrCodeAppConfigSrvFail: "应用配置表服务错误", ErrCodeAppConfigNotExist: "应用配置表不存在", + + ErrCodeMomentCreateTimesSrvFail: "动态创建频次表服务错误", + ErrCodeMomentCreateTimesNotExist: "动态创建频次表不存在", + ErrCodeMomentCreateTimesReachedDailyUpperbound: "动态创建次数已达每日上限", } const ( @@ -340,6 +344,12 @@ const ( ErrCodeAppConfigSrvFail ErrCode = -27001 // 应用配置表服务错误 ErrCodeAppConfigNotExist ErrCode = -27002 // 应用配置表不存在 + // MomentCreateTimes: 25xxx + ErrCodeMomentCreateTimesSrvOk ErrCode = ErrCodeOk + ErrCodeMomentCreateTimesSrvFail ErrCode = -28001 // 动态创建频次表服务错误 + ErrCodeMomentCreateTimesNotExist ErrCode = -28002 // 动态创建频次表不存在 + ErrCodeMomentCreateTimesReachedDailyUpperbound ErrCode = -28003 // 动态创建次数已达每日上限 + // Media: 60xxx ErrCodeMediaSrvOk ErrCode = ErrCodeOk ErrCodeMediaSrvFail ErrCode = -60001 // 媒体服务错误 diff --git a/app/mix/dao/mongo.go b/app/mix/dao/mongo.go index af351a64..70748946 100644 --- a/app/mix/dao/mongo.go +++ b/app/mix/dao/mongo.go @@ -92,8 +92,9 @@ const ( COLVeriCode = "vericode" COLVeriCodeSendTimes = "vericode_send_times" - DBMoment = "moment" - COLMoment = "moment" + DBMoment = "moment" + COLMoment = "moment" + COLMomentCreateTimes = "moment_create_times" DBFootPrint = "footprint" COLFootPrint = "footprint" @@ -234,6 +235,11 @@ func (m *Mongo) getColMoment() *qmgo.Collection { return m.clientMix.Database(DBMoment).Collection(COLMoment) } +// 动态创建频次表 +func (m *Mongo) getColMomentCreateTimes() *qmgo.Collection { + return m.clientMix.Database(DBMoment).Collection(COLMomentCreateTimes) +} + // 足迹表 func (m *Mongo) getColFootPrint() *qmgo.Collection { return m.clientMix.Database(DBFootPrint).Collection(COLFootPrint) @@ -1241,6 +1247,32 @@ func (m *Mongo) ThumbsUpMoment(ctx *gin.Context, req *momentproto.OpThumbsUpReq) return err } +// 动态创建频次 +func (m *Mongo) GetAndUpdateMomentCreateTimes(ctx *gin.Context, mid int64) (momentCreateTimes *dbstruct.MomentCreateTimes, err error) { + col := m.getColMomentCreateTimes() + + change := qmgo.Change{ + Update: qmgo.M{"$inc": qmgo.M{"create_times": 1}}, + Upsert: true, + ReturnNew: false, + } + + momentCreateTimesInstance := dbstruct.MomentCreateTimes{} + if err = col.Find(ctx, qmgo.M{"_id": mid}).Apply(change, &momentCreateTimesInstance); err != nil { + logger.Error("change error : %v", err) + return + } + + return &momentCreateTimesInstance, err +} + +// 清空动态创建频次表 +func (m *Mongo) ClearMomentCreateTimes(ctx *gin.Context) error { + col := m.getColMomentCreateTimes() + _, err := col.RemoveAll(ctx, qmgo.M{}) + return err +} + // 足迹相关 func (m *Mongo) CreateFootPrint(ctx *gin.Context, footprint []*dbstruct.FootPrint) error { col := m.getColFootPrint() diff --git a/app/mix/service/apiservice.go b/app/mix/service/apiservice.go index 5f005528..2924ab88 100644 --- a/app/mix/service/apiservice.go +++ b/app/mix/service/apiservice.go @@ -1585,6 +1585,10 @@ func (s *Service) ApiCreateMoment(ctx *gin.Context, req *momentproto.ApiCreateRe req.Moment.Mid = goproto.Int64(req.BaseRequest.Mid) + if ec = s.ApiCreateMomentBusinessValidate(ctx, req); ec != errcode.ErrCodeMomentSrvOk { + return + } + err := _DefaultMoment.OpCreate(ctx, &momentproto.OpCreateReq{ Moment: req.Moment, }) diff --git a/app/mix/service/apiservice_business_validation.go b/app/mix/service/apiservice_business_validation.go index 2467272f..35c4a439 100644 --- a/app/mix/service/apiservice_business_validation.go +++ b/app/mix/service/apiservice_business_validation.go @@ -6,6 +6,7 @@ import ( accountproto "service/api/proto/account/proto" accountrelationproto "service/api/proto/accountrelation/proto" loginproto "service/api/proto/login/proto" + momentproto "service/api/proto/moment/proto" streamerproto "service/api/proto/streamer/proto" streamerauthapprovalproto "service/api/proto/streamerauthapproval/proto" vericodeproto "service/api/proto/vericode/proto" @@ -522,3 +523,19 @@ func (s *Service) ApiGetStreamerWxIdBusinessValidate(ctx *gin.Context, req *stre return } + +func (s *Service) ApiCreateMomentBusinessValidate(ctx *gin.Context, req *momentproto.ApiCreateReq) (ec errcode.ErrCode) { + + resultList := businessvalidator.NewAuthBusinessValidator(ctx, req). + QueryMomentCreateTimes(_DefaultMomentCreateTimes.OpGetAndUpdate, req.GetBaseRequest().Mid). + EnsureMomentCreateTimesNotReachedDailyUpperbound(). + Validate(). + Collect() + ec, _ = resultList[0].(errcode.ErrCode) + if ec != errcode.ErrCodeLoginSrvOk { + logger.Error("ApiSendVeriCodeBusinessValidate business validation failed!") + return + } + + return +} diff --git a/app/mix/service/business_validator/auth.go b/app/mix/service/business_validator/auth.go index c80edbe2..061c60f6 100644 --- a/app/mix/service/business_validator/auth.go +++ b/app/mix/service/business_validator/auth.go @@ -8,6 +8,7 @@ import ( accountrelationproto "service/api/proto/accountrelation/proto" "service/bizcommon/util" "service/dbstruct" + "service/library/apollo" "service/library/logger" "github.com/gin-gonic/gin" @@ -21,8 +22,9 @@ type AuthBusinessValidator struct { // 操作来源校验 OperMid int64 // 操作用户 - account *dbstruct.Account - accountrelation *dbstruct.AccountRelation + account *dbstruct.Account + accountrelation *dbstruct.AccountRelation + momentCreateTimes *dbstruct.MomentCreateTimes } func NewAuthBusinessValidator(ctx *gin.Context, req any) *AuthBusinessValidator { @@ -260,6 +262,40 @@ func (a *AuthBusinessValidator) ForAccountRelations(accountrelations []*dbstruct return a } +func (l *AuthBusinessValidator) QueryMomentCreateTimes(fun func(*gin.Context, int64) (*dbstruct.MomentCreateTimes, error), mid int64) *AuthBusinessValidator { + l.oplist = append(l.oplist, func() { + + momentCreateTimes, err := fun(l.ctx, mid) + if err != nil { + l.ec = errcode.ErrCodeMomentCreateTimesSrvFail + return + } + + l.momentCreateTimes = momentCreateTimes + }) + return l +} + +func (l *AuthBusinessValidator) EnsureMomentCreateTimesNotReachedDailyUpperbound() *AuthBusinessValidator { + l.oplist = append(l.oplist, func() { + + // 读取每日发送上限 + maxDailyMomentCreateTimes, err := apollo.GetIntValue(consts.MaxDailyMomentCreateTimesKey, apollo.ApolloOpts().SetNamespace("application")) + if err != nil { + logger.Error("Apollo read failed : %v", err) + l.ec = errcode.ErrCodeApolloReadFail + return + } + + if l.momentCreateTimes.CreateTimes >= int64(maxDailyMomentCreateTimes) { + logger.Error("the moment create times of this mid has reached its daily upperbound") + l.ec = errcode.ErrCodeMomentCreateTimesReachedDailyUpperbound + return + } + }) + return l +} + // 执行校验 func (a *AuthBusinessValidator) Validate() *AuthBusinessValidator { a.BusinessValidateStream.Validate() diff --git a/app/mix/service/logic/moment_create_times.go b/app/mix/service/logic/moment_create_times.go new file mode 100644 index 00000000..b2be12e8 --- /dev/null +++ b/app/mix/service/logic/moment_create_times.go @@ -0,0 +1,40 @@ +package logic + +import ( + "service/app/mix/dao" + "service/dbstruct" + "service/library/logger" + + "github.com/gin-gonic/gin" +) + +type MomentCreateTimes struct { + store *dao.Store +} + +func NewMomentCreateTimes(store *dao.Store) (a *MomentCreateTimes) { + a = &MomentCreateTimes{ + store: store, + } + return +} + +func (p *MomentCreateTimes) OpGetAndUpdate(ctx *gin.Context, mid int64) (*dbstruct.MomentCreateTimes, error) { + + vericodeSendTimes, err := p.store.GetAndUpdateMomentCreateTimes(ctx, mid) + if err != nil { + logger.Error("GetAndUpdateMomentCreateTimes fail, err: %v", err) + return nil, err + } + + return vericodeSendTimes, nil +} + +func (p *MomentCreateTimes) OpClear(ctx *gin.Context) error { + err := p.store.ClearMomentCreateTimes(ctx) + if err != nil { + logger.Error("ClearMomentCreateTimes fail, err: %v", err) + return err + } + return nil +} diff --git a/app/mix/service/service.go b/app/mix/service/service.go index 20a451d2..78974d4a 100644 --- a/app/mix/service/service.go +++ b/app/mix/service/service.go @@ -76,6 +76,7 @@ var ( _DefaultBanner *logic.Banner _DefaultLogin *logic.Login _DefaultMoment *logic.Moment + _DefaultMomentCreateTimes *logic.MomentCreateTimes _DefaultFootPrint *logic.FootPrint _DefaultThumbsUp *logic.ThumbsUp _DefaultAccountRelation *logic.AccountRelation @@ -142,6 +143,7 @@ func (s *Service) Init(c any) (err error) { _DefaultBanner = logic.NewBanner(store) _DefaultLogin = logic.NewLogin(store) _DefaultMoment = logic.NewMoment(store) + _DefaultMomentCreateTimes = logic.NewMomentCreateTimes(store) _DefaultFootPrint = logic.NewFootPrint(store) _DefaultThumbsUp = logic.NewThumbsUp(store) _DefaultAccountRelation = logic.NewAccountRelation(store) diff --git a/dbstruct/moment_create_times.go b/dbstruct/moment_create_times.go new file mode 100644 index 00000000..6e7e6276 --- /dev/null +++ b/dbstruct/moment_create_times.go @@ -0,0 +1,6 @@ +package dbstruct + +type MomentCreateTimes struct { + Id int64 `json:"id" bson:"_id"` //id,主播的mid + CreateTimes int64 `json:"create_times" bson:"create_times"` //发送次数 +}