| @@ -91,6 +91,23 @@ type Action struct { | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| } | |||
| type ActionShow struct { | |||
| UserID int64 | |||
| OpType ActionType | |||
| ActUserID int64 | |||
| ActUser *UserShow | |||
| RepoID int64 | |||
| Repo *RepositoryShow | |||
| CommentID int64 | |||
| Comment *Comment `xorm:"-"` | |||
| IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| RefName string | |||
| IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| Content string `xorm:"TEXT"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| } | |||
| // GetOpType gets the ActionType of this action. | |||
| func (a *Action) GetOpType() ActionType { | |||
| return a.OpType | |||
| @@ -237,6 +237,12 @@ type Repository struct { | |||
| LowerAlias string `xorm:"INDEX"` | |||
| } | |||
| type RepositoryShow struct { | |||
| Name string | |||
| RepoType RepoType | |||
| Alias string | |||
| } | |||
| // SanitizedOriginalURL returns a sanitized OriginalURL | |||
| func (repo *Repository) SanitizedOriginalURL() string { | |||
| if repo.OriginalURL == "" { | |||
| @@ -213,21 +213,22 @@ func (l *RewardRecordList) GetRewardRecordCloudbrainTask() (map[string]Cloudbrai | |||
| } | |||
| type RewardOperateRecord struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| SerialNo string `xorm:"INDEX NOT NULL"` | |||
| UserId int64 `xorm:"INDEX NOT NULL"` | |||
| Amount int64 `xorm:"NOT NULL"` | |||
| Tittle string | |||
| RewardType string `xorm:"NOT NULL"` | |||
| SourceType string `xorm:"NOT NULL"` | |||
| SourceId string `xorm:"INDEX NOT NULL"` | |||
| RequestId string `xorm:"INDEX NOT NULL"` | |||
| OperateType string `xorm:"NOT NULL"` | |||
| Status string `xorm:"NOT NULL"` | |||
| Remark string | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| FinishedUnix timeutil.TimeStamp `xorm:"INDEX"` | |||
| ID int64 `xorm:"pk autoincr"` | |||
| SerialNo string `xorm:"INDEX NOT NULL"` | |||
| UserId int64 `xorm:"INDEX NOT NULL"` | |||
| Amount int64 `xorm:"NOT NULL"` | |||
| LossAmount int64 | |||
| Tittle string | |||
| RewardType string `xorm:"NOT NULL"` | |||
| SourceType string `xorm:"NOT NULL"` | |||
| SourceId string `xorm:"INDEX NOT NULL"` | |||
| RequestId string `xorm:"INDEX NOT NULL"` | |||
| OperateType string `xorm:"NOT NULL"` | |||
| Status string `xorm:"NOT NULL"` | |||
| Remark string | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| LastOperateUnix timeutil.TimeStamp `xorm:"INDEX"` | |||
| } | |||
| type AdminRewardOperateReq struct { | |||
| @@ -240,27 +241,31 @@ type AdminRewardOperateReq struct { | |||
| func (r RewardOperateRecord) ToShow() RewardOperateRecordShow { | |||
| return RewardOperateRecordShow{ | |||
| SerialNo: r.SerialNo, | |||
| Date: r.CreatedUnix, | |||
| OperateType: r.OperateType, | |||
| Amount: r.Amount, | |||
| Remark: r.Remark, | |||
| Status: r.Status, | |||
| SourceType: r.SourceType, | |||
| SerialNo: r.SerialNo, | |||
| Date: r.CreatedUnix, | |||
| OperateType: r.OperateType, | |||
| Amount: r.Amount, | |||
| Remark: r.Remark, | |||
| Status: r.Status, | |||
| SourceType: r.SourceType, | |||
| LastOperateTask: r.LastOperateUnix, | |||
| LossAmount: r.LossAmount, | |||
| } | |||
| } | |||
| type RewardOperateRecordShow struct { | |||
| SerialNo string | |||
| Date timeutil.TimeStamp | |||
| Status string | |||
| OperateType string | |||
| Amount int64 | |||
| Remark string | |||
| SourceType string | |||
| Action Action | |||
| Cloudbrain Cloudbrain | |||
| AdminLog RewardAdminLog | |||
| SerialNo string | |||
| Date timeutil.TimeStamp | |||
| Status string | |||
| OperateType string | |||
| Amount int64 | |||
| LossAmount int64 | |||
| Remark string | |||
| SourceType string | |||
| LastOperateTask timeutil.TimeStamp | |||
| Action Action | |||
| Cloudbrain Cloudbrain | |||
| AdminLog RewardAdminLog | |||
| } | |||
| func getPointOperateRecord(tl *RewardOperateRecord) (*RewardOperateRecord, error) { | |||
| @@ -295,10 +300,10 @@ func InsertRewardOperateRecord(tl *RewardOperateRecord) (int64, error) { | |||
| func UpdateRewardRecordToFinalStatus(sourceType, requestId, newStatus string) (int64, error) { | |||
| r := &RewardOperateRecord{ | |||
| Status: newStatus, | |||
| FinishedUnix: timeutil.TimeStampNow(), | |||
| Status: newStatus, | |||
| LastOperateUnix: timeutil.TimeStampNow(), | |||
| } | |||
| return x.Cols("status", "finished_unix").Where("source_type=? and request_id=? and status=?", sourceType, requestId, OperateStatusOperating).Update(r) | |||
| return x.Cols("status", "last_operate_unix").Where("source_type=? and request_id=? and status=?", sourceType, requestId, OperateStatusOperating).Update(r) | |||
| } | |||
| func SumRewardAmountInTaskPeriod(rewardType string, sourceType string, userId int64, period *PeriodResult) (int64, error) { | |||
| @@ -326,6 +331,7 @@ type RewardOperateContext struct { | |||
| OperateType RewardOperateType | |||
| RejectPolicy LimiterRejectPolicy | |||
| PermittedNegative bool | |||
| LossAmount int64 | |||
| } | |||
| type Reward struct { | |||
| @@ -77,7 +77,7 @@ func IncrRewardTaskSuccessCount(t RewardPeriodicTask, count int64, nextTime time | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| _, err = sess.Exec("update reward_operate_record set amount = amount + ? ,updated_unix = ? where serial_no = ?", t.Amount, timeutil.TimeStampNow(), t.OperateSerialNo) | |||
| _, err = sess.Exec("update reward_operate_record set amount = amount + ? ,updated_unix = ? ,last_operate_unix = ? where serial_no = ?", t.Amount, timeutil.TimeStampNow(), timeutil.TimeStampNow(), t.OperateSerialNo) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| @@ -186,6 +186,10 @@ type User struct { | |||
| WechatBindUnix timeutil.TimeStamp | |||
| } | |||
| type UserShow struct { | |||
| Name string | |||
| } | |||
| // SearchOrganizationsOptions options to filter organizations | |||
| type SearchOrganizationsOptions struct { | |||
| ListOptions | |||
| @@ -59,7 +59,7 @@ func StartCloudbrainPointDeductTask() { | |||
| }() | |||
| log.Debug("try to run CloudbrainPointDeductTask") | |||
| end := time.Now() | |||
| start := end.Add(-5 * time.Minute) | |||
| start := end.Add(-30 * time.Minute) | |||
| if firstTimeFlag { | |||
| //When it is executed for the first time, it needs to process the tasks of the last 1 hours. | |||
| //This is done to prevent the application from hanging for a long time | |||
| @@ -76,30 +76,35 @@ func StartCloudbrainPointDeductTask() { | |||
| return | |||
| } | |||
| for _, t := range taskList { | |||
| //初始化 period_task 和 operate_record | |||
| if int64(t.StartTime) > end.Unix() || int64(t.StartTime) < start.Unix() { | |||
| continue | |||
| } | |||
| DeductPoint4Cloudbrain(t, end) | |||
| } | |||
| } | |||
| task, err := StartAndGetCloudBrainPointDeductTask(t) | |||
| if err != nil { | |||
| log.Error("run cloubrain point deduct task error,err=%v", err) | |||
| continue | |||
| } | |||
| if task == nil { | |||
| continue | |||
| } | |||
| if task.Status == models.PeriodicTaskStatusFinished { | |||
| log.Info("Periodic task is finished") | |||
| continue | |||
| } | |||
| func DeductPoint4Cloudbrain(t models.Cloudbrain, now time.Time) error { | |||
| if int64(t.EndTime) <= end.Unix() && int64(t.EndTime) >= start.Unix() { | |||
| endTime := time.Unix(int64(t.EndTime), 0) | |||
| RunRewardTask(*task, endTime) | |||
| models.StopPeriodicTask(task.ID, task.OperateSerialNo, endTime) | |||
| } else { | |||
| RunRewardTask(*task, end) | |||
| } | |||
| if t.StartTime == 0 { | |||
| return nil | |||
| } | |||
| task, err := StartAndGetCloudBrainPointDeductTask(t) | |||
| if err != nil { | |||
| log.Error("run cloudbrain point deduct task error,err=%v", err) | |||
| return err | |||
| } | |||
| if task == nil { | |||
| return nil | |||
| } | |||
| if task.Status == models.PeriodicTaskStatusFinished { | |||
| log.Info("Periodic task is finished") | |||
| return nil | |||
| } | |||
| if t.EndTime > 0 { | |||
| endTime := time.Unix(int64(t.EndTime), 0) | |||
| RunRewardTask(*task, endTime) | |||
| models.StopPeriodicTask(task.ID, task.OperateSerialNo, endTime) | |||
| } else { | |||
| RunRewardTask(*task, now) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -35,7 +35,7 @@ func GetRewardOperation(since, until timeutil.TimeStamp) []models.UserRewardOper | |||
| json.Unmarshal([]byte(v), &t) | |||
| r = append(r, models.UserRewardOperation{ | |||
| UserId: t.UserId, | |||
| Msg: GetRewardOperateMsg(t), | |||
| Msg: v, | |||
| }) | |||
| } | |||
| redis_client.ZRemRangeByScore(redis_key.RewardOperateNotification(), float64(since), float64(until)) | |||
| @@ -118,6 +118,7 @@ func initRewardOperateRecord(ctx *models.RewardOperateContext) (string, error) { | |||
| record := &models.RewardOperateRecord{ | |||
| UserId: ctx.TargetUserId, | |||
| Amount: ctx.Reward.Amount, | |||
| LossAmount: ctx.LossAmount, | |||
| RewardType: ctx.Reward.Type.Name(), | |||
| SourceType: ctx.SourceType.Name(), | |||
| SourceId: ctx.SourceId, | |||
| @@ -77,7 +77,7 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) error { | |||
| return errors.New("operator of reward type is not exist") | |||
| } | |||
| nextTime := t.NextExecuteTime | |||
| for i := 0; int64(i) <= n; i++ { | |||
| for i := 1; int64(i) <= n; i++ { | |||
| err = operator.Operate(&models.RewardOperateContext{ | |||
| SourceType: models.SourceTypeRunCloudbrainTask, | |||
| SourceId: t.OperateSerialNo, | |||
| @@ -97,6 +97,7 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) error { | |||
| return err | |||
| } | |||
| repo.StopJobs([]*models.Cloudbrain{task}) | |||
| models.StopPeriodicTask(task.ID, t.OperateSerialNo, time.Now()) | |||
| return nil | |||
| } | |||
| return nil | |||
| @@ -9,12 +9,9 @@ import ( | |||
| "code.gitea.io/gitea/services/reward/limiter" | |||
| "code.gitea.io/gitea/services/reward/point/account" | |||
| "errors" | |||
| "fmt" | |||
| "time" | |||
| ) | |||
| const LossMsg = "达到奖励上限,应得%d积分,实得%d积分" | |||
| type PointOperator struct { | |||
| } | |||
| @@ -24,7 +21,7 @@ func (operator *PointOperator) IsLimited(ctx *models.RewardOperateContext) error | |||
| return err | |||
| } | |||
| if realAmount < ctx.Reward.Amount { | |||
| ctx.Remark = models.AppendRemark(ctx.Remark, fmt.Sprintf(LossMsg, ctx.Reward.Amount, realAmount)) | |||
| ctx.LossAmount = ctx.Reward.Amount - realAmount | |||
| ctx.Reward.Amount = realAmount | |||
| } | |||
| return nil | |||
| @@ -49,7 +46,7 @@ func (operator *PointOperator) Operate(ctx *models.RewardOperateContext) error { | |||
| } 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{} | |||
| return models.ErrInsufficientPointsBalance{} | |||
| } | |||
| err = na.Decrease(ctx.Reward.Amount, ctx.SourceId) | |||
| } | |||