| @@ -141,18 +141,22 @@ func (r RewardOperateRecord) ToShow() RewardOperateRecordShow { | |||||
| return RewardOperateRecordShow{ | return RewardOperateRecordShow{ | ||||
| SerialNo: r.SerialNo, | SerialNo: r.SerialNo, | ||||
| Date: r.CreatedUnix, | Date: r.CreatedUnix, | ||||
| Tittle: r.Tittle, | |||||
| OperateType: r.OperateType, | OperateType: r.OperateType, | ||||
| Amount: r.Amount, | Amount: r.Amount, | ||||
| Remark: r.Remark, | |||||
| } | } | ||||
| } | } | ||||
| type RewardOperateRecordShow struct { | type RewardOperateRecordShow struct { | ||||
| SerialNo string | SerialNo string | ||||
| Date timeutil.TimeStamp | Date timeutil.TimeStamp | ||||
| Tittle string | |||||
| Status string | |||||
| OperateType string | OperateType string | ||||
| Amount int64 | Amount int64 | ||||
| Action Action | |||||
| Cloudbrain Cloudbrain | |||||
| SourceType SourceType | |||||
| Remark string | |||||
| } | } | ||||
| func getPointOperateRecord(tl *RewardOperateRecord) (*RewardOperateRecord, error) { | func getPointOperateRecord(tl *RewardOperateRecord) (*RewardOperateRecord, error) { | ||||
| @@ -207,15 +211,16 @@ func SumRewardAmountInTaskPeriod(rewardType string, sourceType string, userId in | |||||
| } | } | ||||
| type RewardOperateContext struct { | type RewardOperateContext struct { | ||||
| SourceType SourceType | |||||
| SourceId string | |||||
| Tittle string | |||||
| Remark string | |||||
| Reward Reward | |||||
| TargetUserId int64 | |||||
| RequestId string | |||||
| OperateType RewardOperateType | |||||
| RejectPolicy LimiterRejectPolicy | |||||
| SourceType SourceType | |||||
| SourceId string | |||||
| Tittle string | |||||
| Remark string | |||||
| Reward Reward | |||||
| TargetUserId int64 | |||||
| RequestId string | |||||
| OperateType RewardOperateType | |||||
| RejectPolicy LimiterRejectPolicy | |||||
| PermittedNegative bool | |||||
| } | } | ||||
| type Reward struct { | type Reward struct { | ||||
| @@ -2,6 +2,7 @@ package point | |||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/base" | |||||
| "code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
| "code.gitea.io/gitea/routers/response" | "code.gitea.io/gitea/routers/response" | ||||
| "code.gitea.io/gitea/services/reward" | "code.gitea.io/gitea/services/reward" | ||||
| @@ -9,6 +10,8 @@ import ( | |||||
| "net/http" | "net/http" | ||||
| ) | ) | ||||
| const tplPoint base.TplName = "/reward/point" | |||||
| type AccountResponse struct { | type AccountResponse struct { | ||||
| AccountCode string | AccountCode string | ||||
| Balance int64 | Balance int64 | ||||
| @@ -24,7 +27,6 @@ func GetPointAccount(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| res := &AccountResponse{ | res := &AccountResponse{ | ||||
| AccountCode: a.AccountCode, | |||||
| Balance: a.Balance, | Balance: a.Balance, | ||||
| TotalEarned: a.TotalEarned, | TotalEarned: a.TotalEarned, | ||||
| TotalConsumed: a.TotalConsumed, | TotalConsumed: a.TotalConsumed, | ||||
| @@ -75,3 +77,7 @@ func OperatePointAccountBalance(ctx *context.Context, req models.AdminRewardOper | |||||
| } | } | ||||
| ctx.JSON(http.StatusOK, response.Success()) | ctx.JSON(http.StatusOK, response.Success()) | ||||
| } | } | ||||
| func GetPointPage(ctx *context.Context) { | |||||
| ctx.HTML(200, tplPoint) | |||||
| } | |||||
| @@ -595,6 +595,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }) | }) | ||||
| m.Group("/reward/point", func() { | m.Group("/reward/point", func() { | ||||
| m.Get("", point.GetPointPage) | |||||
| m.Get("/limiter/list", point.GetPointLimitConfigList) | m.Get("/limiter/list", point.GetPointLimitConfigList) | ||||
| m.Post("/limiter/add", bindIgnErr(models.LimitConfigVO{}), point.AddPointLimitConfig) | m.Post("/limiter/add", bindIgnErr(models.LimitConfigVO{}), point.AddPointLimitConfig) | ||||
| m.Post("/limiter/delete", point.DeletePointLimitConfig) | m.Post("/limiter/delete", point.DeletePointLimitConfig) | ||||
| @@ -32,11 +32,12 @@ func AdminBalanceOperate(req models.AdminRewardOperateReq, doer *models.User) er | |||||
| Amount: req.Amount, | Amount: req.Amount, | ||||
| Type: req.RewardType, | Type: req.RewardType, | ||||
| }, | }, | ||||
| TargetUserId: req.TargetUserId, | |||||
| RequestId: logId, | |||||
| OperateType: req.OperateType, | |||||
| Remark: req.Remark, | |||||
| RejectPolicy: models.JustReject, | |||||
| TargetUserId: req.TargetUserId, | |||||
| RequestId: logId, | |||||
| OperateType: req.OperateType, | |||||
| Remark: req.Remark, | |||||
| RejectPolicy: models.JustReject, | |||||
| PermittedNegative: true, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -63,31 +63,41 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) { | |||||
| log.Info("RunRewardTask. operate record is finished,record=%+v", record) | log.Info("RunRewardTask. operate record is finished,record=%+v", record) | ||||
| return | return | ||||
| } | } | ||||
| n, nextTime := countExecuteTimes(t, now) | |||||
| n, _ := countExecuteTimes(t, now) | |||||
| if n == 0 { | if n == 0 { | ||||
| return | return | ||||
| } | } | ||||
| //get operator | //get operator | ||||
| operator := GetOperator(models.GetRewardTypeInstance(record.RewardType)) | operator := GetOperator(models.GetRewardTypeInstance(record.RewardType)) | ||||
| if operator == nil { | if operator == nil { | ||||
| log.Error("RunRewardTask. operator of reward type is not exist") | log.Error("RunRewardTask. operator of reward type is not exist") | ||||
| return | return | ||||
| } | } | ||||
| err = operator.Operate(&models.RewardOperateContext{ | |||||
| SourceType: models.SourceTypeRunCloudbrainTask, | |||||
| SourceId: t.OperateSerialNo, | |||||
| Reward: models.Reward{ | |||||
| Amount: n * t.Amount, | |||||
| Type: models.GetRewardTypeInstance(record.RewardType), | |||||
| }, | |||||
| TargetUserId: record.UserId, | |||||
| OperateType: models.GetRewardOperateTypeInstance(record.OperateType), | |||||
| }) | |||||
| if err != nil { | |||||
| log.Error("RunRewardTask.operator operate error.%v", err) | |||||
| return | |||||
| nextTime := t.NextExecuteTime | |||||
| for i := 0; int64(i) <= n; i++ { | |||||
| err = operator.Operate(&models.RewardOperateContext{ | |||||
| SourceType: models.SourceTypeRunCloudbrainTask, | |||||
| SourceId: t.OperateSerialNo, | |||||
| Reward: models.Reward{ | |||||
| Amount: t.Amount, | |||||
| Type: models.GetRewardTypeInstance(record.RewardType), | |||||
| }, | |||||
| TargetUserId: record.UserId, | |||||
| OperateType: models.GetRewardOperateTypeInstance(record.OperateType), | |||||
| }) | |||||
| if err != nil { | |||||
| log.Error("RunRewardTask.operator operate error.%v", err) | |||||
| if models.IsErrInsufficientPointsBalance(err) { | |||||
| StopCloudbrainTask(record) | |||||
| return | |||||
| } | |||||
| return | |||||
| } | |||||
| models.IncrRewardTaskSuccessCount(t, n, nextTime) | |||||
| nextTime = timeutil.TimeStamp(int64(nextTime) + t.IntervalSeconds) | |||||
| } | } | ||||
| models.IncrRewardTaskSuccessCount(t, n, nextTime) | |||||
| } | } | ||||
| func countExecuteTimes(t models.RewardPeriodicTask, now time.Time) (int64, timeutil.TimeStamp) { | func countExecuteTimes(t models.RewardPeriodicTask, now time.Time) (int64, timeutil.TimeStamp) { | ||||
| @@ -101,3 +111,8 @@ func countExecuteTimes(t models.RewardPeriodicTask, now time.Time) (int64, timeu | |||||
| newNextTime := timeutil.TimeStamp(nextTime + n*interval) | newNextTime := timeutil.TimeStamp(nextTime + n*interval) | ||||
| return n, newNextTime | return n, newNextTime | ||||
| } | } | ||||
| func StopCloudbrainTask(r *models.RewardOperateRecord) { | |||||
| //todo | |||||
| } | |||||
| @@ -2,6 +2,7 @@ package point | |||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/redis/redis_client" | "code.gitea.io/gitea/modules/redis/redis_client" | ||||
| "code.gitea.io/gitea/modules/redis/redis_key" | "code.gitea.io/gitea/modules/redis/redis_key" | ||||
| "code.gitea.io/gitea/modules/redis/redis_lock" | "code.gitea.io/gitea/modules/redis/redis_lock" | ||||
| @@ -46,6 +47,10 @@ func (operator *PointOperator) Operate(ctx *models.RewardOperateContext) error { | |||||
| if ctx.OperateType == models.OperateTypeIncrease { | if ctx.OperateType == models.OperateTypeIncrease { | ||||
| err = na.Increase(ctx.Reward.Amount, ctx.SourceId) | err = na.Increase(ctx.Reward.Amount, ctx.SourceId) | ||||
| } else if ctx.OperateType == models.OperateTypeDecrease { | } else if ctx.OperateType == models.OperateTypeDecrease { | ||||
| if !ctx.PermittedNegative && na.Balance < ctx.Reward.Amount { | |||||
| log.Info("account balance is not enough,ctx=%v", ctx) | |||||
| return &models.ErrInsufficientPointsBalance{} | |||||
| } | |||||
| err = na.Decrease(ctx.Reward.Amount, ctx.SourceId) | err = na.Decrease(ctx.Reward.Amount, ctx.SourceId) | ||||
| } | } | ||||
| if err != nil { | if err != nil { | ||||
| @@ -3,8 +3,10 @@ package reward | |||||
| import "code.gitea.io/gitea/models" | import "code.gitea.io/gitea/models" | ||||
| type RecordResponse struct { | type RecordResponse struct { | ||||
| Records []models.RewardOperateRecordShow | |||||
| Total int64 | |||||
| Records []models.RewardOperateRecordShow | |||||
| Total int64 | |||||
| PageSize int | |||||
| Page int | |||||
| } | } | ||||
| func GetRewardRecordList(opts models.RewardRecordListOpts) (*RecordResponse, error) { | func GetRewardRecordList(opts models.RewardRecordListOpts) (*RecordResponse, error) { | ||||
| @@ -16,5 +18,5 @@ func GetRewardRecordList(opts models.RewardRecordListOpts) (*RecordResponse, err | |||||
| for _, v := range l { | for _, v := range l { | ||||
| r = append(r, v.ToShow()) | r = append(r, v.ToShow()) | ||||
| } | } | ||||
| return &RecordResponse{Records: r, Total: n}, nil | |||||
| return &RecordResponse{Records: r, Total: n, Page: opts.Page, PageSize: opts.PageSize}, nil | |||||
| } | } | ||||