| @@ -141,18 +141,22 @@ func (r RewardOperateRecord) ToShow() RewardOperateRecordShow { | |||
| return RewardOperateRecordShow{ | |||
| SerialNo: r.SerialNo, | |||
| Date: r.CreatedUnix, | |||
| Tittle: r.Tittle, | |||
| OperateType: r.OperateType, | |||
| Amount: r.Amount, | |||
| Remark: r.Remark, | |||
| } | |||
| } | |||
| type RewardOperateRecordShow struct { | |||
| SerialNo string | |||
| Date timeutil.TimeStamp | |||
| Tittle string | |||
| Status string | |||
| OperateType string | |||
| Amount int64 | |||
| Action Action | |||
| Cloudbrain Cloudbrain | |||
| SourceType SourceType | |||
| Remark string | |||
| } | |||
| func getPointOperateRecord(tl *RewardOperateRecord) (*RewardOperateRecord, error) { | |||
| @@ -207,15 +211,16 @@ func SumRewardAmountInTaskPeriod(rewardType string, sourceType string, userId in | |||
| } | |||
| 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 { | |||
| @@ -2,6 +2,7 @@ package point | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/base" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/routers/response" | |||
| "code.gitea.io/gitea/services/reward" | |||
| @@ -9,6 +10,8 @@ import ( | |||
| "net/http" | |||
| ) | |||
| const tplPoint base.TplName = "/reward/point" | |||
| type AccountResponse struct { | |||
| AccountCode string | |||
| Balance int64 | |||
| @@ -24,7 +27,6 @@ func GetPointAccount(ctx *context.Context) { | |||
| return | |||
| } | |||
| res := &AccountResponse{ | |||
| AccountCode: a.AccountCode, | |||
| Balance: a.Balance, | |||
| TotalEarned: a.TotalEarned, | |||
| TotalConsumed: a.TotalConsumed, | |||
| @@ -75,3 +77,7 @@ func OperatePointAccountBalance(ctx *context.Context, req models.AdminRewardOper | |||
| } | |||
| 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.Get("", point.GetPointPage) | |||
| m.Get("/limiter/list", point.GetPointLimitConfigList) | |||
| m.Post("/limiter/add", bindIgnErr(models.LimitConfigVO{}), point.AddPointLimitConfig) | |||
| m.Post("/limiter/delete", point.DeletePointLimitConfig) | |||
| @@ -32,11 +32,12 @@ func AdminBalanceOperate(req models.AdminRewardOperateReq, doer *models.User) er | |||
| Amount: req.Amount, | |||
| 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 { | |||
| @@ -63,31 +63,41 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) { | |||
| log.Info("RunRewardTask. operate record is finished,record=%+v", record) | |||
| return | |||
| } | |||
| n, nextTime := countExecuteTimes(t, now) | |||
| n, _ := countExecuteTimes(t, now) | |||
| if n == 0 { | |||
| return | |||
| } | |||
| //get operator | |||
| operator := GetOperator(models.GetRewardTypeInstance(record.RewardType)) | |||
| if operator == nil { | |||
| log.Error("RunRewardTask. operator of reward type is not exist") | |||
| 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) { | |||
| @@ -101,3 +111,8 @@ func countExecuteTimes(t models.RewardPeriodicTask, now time.Time) (int64, timeu | |||
| newNextTime := timeutil.TimeStamp(nextTime + n*interval) | |||
| return n, newNextTime | |||
| } | |||
| func StopCloudbrainTask(r *models.RewardOperateRecord) { | |||
| //todo | |||
| } | |||
| @@ -2,6 +2,7 @@ package point | |||
| import ( | |||
| "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_key" | |||
| "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 { | |||
| err = na.Increase(ctx.Reward.Amount, ctx.SourceId) | |||
| } 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) | |||
| } | |||
| if err != nil { | |||
| @@ -3,8 +3,10 @@ package reward | |||
| import "code.gitea.io/gitea/models" | |||
| type RecordResponse struct { | |||
| Records []models.RewardOperateRecordShow | |||
| Total int64 | |||
| Records []models.RewardOperateRecordShow | |||
| Total int64 | |||
| PageSize int | |||
| Page int | |||
| } | |||
| func GetRewardRecordList(opts models.RewardRecordListOpts) (*RecordResponse, error) { | |||
| @@ -16,5 +18,5 @@ func GetRewardRecordList(opts models.RewardRecordListOpts) (*RecordResponse, err | |||
| for _, v := range l { | |||
| 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 | |||
| } | |||