| @@ -58,6 +58,16 @@ const ( | |||
| ActionCreateBenchMarkTask //29 | |||
| ActionCreateNewModelTask //30 | |||
| ActionCreateGPUTrainTask //31 | |||
| ActionBindWechat //32issue_assignees | |||
| ActionCreateCloudbrainTask //33 | |||
| ActionDatasetRecommended //34 | |||
| ActionCreateImage //35 | |||
| ActionImageRecommend //36 | |||
| ActionChangeUserAvatar //37 | |||
| ActionPushCommits //38 | |||
| ActionForkRepo //39 | |||
| ) | |||
| // Action represents user operation type and other information to | |||
| @@ -654,9 +654,9 @@ func Attachments(opts *AttachmentsOptions) ([]*AttachmentInfo, int64, error) { | |||
| return attachments, count, nil | |||
| } | |||
| func GetAllUserIdByDatasetId(datasetId int64) ([]int64, error) { | |||
| r := make([]int64, 0) | |||
| if err := x.Table("attachment").Where("dataset_id = ?", datasetId).Distinct("uploader_id").Find(&r); err != nil { | |||
| func GetAllDatasetContributorByDatasetId(datasetId int64) ([]*User, error) { | |||
| r := make([]*User, 0) | |||
| if err := x.Select("distinct(user.*)").Table("attachment").Join("LEFT", "user", "user.ID = attachment.uploader_id").Where("attachment.dataset_id = ?", datasetId).Find(&r); err != nil { | |||
| return nil, err | |||
| } | |||
| return r, nil | |||
| @@ -2024,3 +2024,15 @@ func IsErrRecordNotExist(err error) bool { | |||
| func (err ErrRecordNotExist) Error() string { | |||
| return fmt.Sprintf("record not exist in database") | |||
| } | |||
| type ErrInsufficientPointsBalance struct { | |||
| } | |||
| func IsErrInsufficientPointsBalance(err error) bool { | |||
| _, ok := err.(ErrInsufficientPointsBalance) | |||
| return ok | |||
| } | |||
| func (err ErrInsufficientPointsBalance) Error() string { | |||
| return fmt.Sprintf("Insufficient points balance") | |||
| } | |||
| @@ -41,6 +41,14 @@ func (l LimitScope) Name() string { | |||
| } | |||
| } | |||
| type LimiterRejectPolicy string | |||
| const ( | |||
| JustReject LimiterRejectPolicy = "JUST_REJECT" | |||
| PermittedOnce LimiterRejectPolicy = "PERMITTED_ONCE" | |||
| FillUp LimiterRejectPolicy = "FillUp" | |||
| ) | |||
| type LimitConfig struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Tittle string | |||
| @@ -151,6 +151,7 @@ func init() { | |||
| new(RewardPeriodicTask), | |||
| new(PointAccountLog), | |||
| new(PointAccount), | |||
| new(RewardAdminLog), | |||
| ) | |||
| tablesStatistic = append(tablesStatistic, | |||
| @@ -25,6 +25,7 @@ const ( | |||
| ) | |||
| var ActionChan = make(chan *Action, 200) | |||
| var ActionChan4Task = make(chan Action, 200) | |||
| // Watch is connection request for receiving repository notification. | |||
| type Watch struct { | |||
| @@ -199,6 +200,9 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
| if _, err = e.InsertOne(act); err != nil { | |||
| return fmt.Errorf("insert new actioner: %v", err) | |||
| } | |||
| // After InsertOne(act),the act has ID | |||
| // Send the act to task chan | |||
| ActionChan4Task <- *act | |||
| if repoChanged { | |||
| act.loadRepo() | |||
| @@ -279,7 +283,6 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
| // NotifyWatchers creates batch of actions for every watcher. | |||
| func NotifyWatchers(actions ...*Action) error { | |||
| error := notifyWatchers(x, actions...) | |||
| producer(actions...) | |||
| return error | |||
| @@ -0,0 +1,46 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| const ( | |||
| RewardAdminLogProcessing = 1 | |||
| RewardAdminLogSuccess = 2 | |||
| RewardAdminLogFailed = 3 | |||
| ) | |||
| type RewardAdminLog struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| LogId string `xorm:"INDEX NOT NULL"` | |||
| Amount int64 `xorm:"NOT NULL"` | |||
| RewardType string | |||
| Remark string | |||
| Status int | |||
| TargetUserId int64 `xorm:"INDEX NOT NULL"` | |||
| CreatorId int64 `xorm:"NOT NULL"` | |||
| CreatorName string | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| } | |||
| func getRewardAdminLog(ra *RewardAdminLog) (*RewardAdminLog, error) { | |||
| has, err := x.Get(ra) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, ErrRecordNotExist{} | |||
| } | |||
| return ra, nil | |||
| } | |||
| func InsertRewardAdminLog(ra *RewardAdminLog) (int64, error) { | |||
| return x.Insert(ra) | |||
| } | |||
| func UpdateRewardAdminLogStatus(logId string, oldStatus, newStatus int) error { | |||
| _, err := x.Where("log_id = ? and status = ?", logId, oldStatus).Update(&RewardAdminLog{Status: newStatus}) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| @@ -95,6 +95,7 @@ func GetRewardOperateTypeInstance(s string) RewardOperateType { | |||
| const ( | |||
| OperateTypeIncrease RewardOperateType = "INCREASE" | |||
| OperateTypeDecrease RewardOperateType = "DECREASE" | |||
| OperateTypeNull RewardOperateType = "NIL" | |||
| ) | |||
| const ( | |||
| @@ -105,11 +106,18 @@ const ( | |||
| const Semicolon = ";" | |||
| type RewardOperateOrderBy string | |||
| const ( | |||
| RewardOrderByID RewardOperateOrderBy = "id" | |||
| ) | |||
| type RewardOperateRecord struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RecordId string `xorm:"INDEX NOT NULL"` | |||
| 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"` | |||
| @@ -121,6 +129,32 @@ type RewardOperateRecord struct { | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| } | |||
| type AdminRewardOperateReq struct { | |||
| TargetUserId int64 `binding:"Required"` | |||
| OperateType RewardOperateType `binding:"Required"` | |||
| Amount int64 `binding:"Required;Range(1,100000)"` | |||
| Remark string | |||
| RewardType RewardType | |||
| } | |||
| func (r RewardOperateRecord) ToShow() RewardOperateRecordShow { | |||
| return RewardOperateRecordShow{ | |||
| SerialNo: r.SerialNo, | |||
| Date: r.CreatedUnix, | |||
| Tittle: r.Tittle, | |||
| OperateType: r.OperateType, | |||
| Amount: r.Amount, | |||
| } | |||
| } | |||
| type RewardOperateRecordShow struct { | |||
| SerialNo string | |||
| Date timeutil.TimeStamp | |||
| Tittle string | |||
| OperateType string | |||
| Amount int64 | |||
| } | |||
| func getPointOperateRecord(tl *RewardOperateRecord) (*RewardOperateRecord, error) { | |||
| has, err := x.Get(tl) | |||
| if err != nil { | |||
| @@ -140,14 +174,14 @@ func GetPointOperateRecordBySourceTypeAndRequestId(sourceType, requestId, operat | |||
| return getPointOperateRecord(t) | |||
| } | |||
| func GetPointOperateRecordByRecordId(recordId string) (*RewardOperateRecord, error) { | |||
| func GetPointOperateRecordBySerialNo(serialNo string) (*RewardOperateRecord, error) { | |||
| t := &RewardOperateRecord{ | |||
| RecordId: recordId, | |||
| SerialNo: serialNo, | |||
| } | |||
| return getPointOperateRecord(t) | |||
| } | |||
| func InsertAwardOperateRecord(tl *RewardOperateRecord) (int64, error) { | |||
| func InsertRewardOperateRecord(tl *RewardOperateRecord) (int64, error) { | |||
| return x.Insert(tl) | |||
| } | |||
| @@ -175,11 +209,13 @@ 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 | |||
| } | |||
| type Reward struct { | |||
| @@ -202,3 +238,43 @@ type UserRewardOperation struct { | |||
| func AppendRemark(remark, appendStr string) string { | |||
| return strings.TrimPrefix(remark+Semicolon+appendStr, Semicolon) | |||
| } | |||
| type RewardRecordListOpts struct { | |||
| ListOptions | |||
| UserId int64 | |||
| OperateType RewardOperateType | |||
| RewardType RewardType | |||
| OrderBy RewardOperateOrderBy | |||
| } | |||
| func GetRewardRecordList(opts RewardRecordListOpts) ([]RewardOperateRecord, int64, error) { | |||
| if opts.Page <= 0 { | |||
| opts.Page = 1 | |||
| } | |||
| if len(opts.OrderBy) == 0 { | |||
| opts.OrderBy = RewardOrderByID | |||
| } | |||
| r := make([]RewardOperateRecord, 0) | |||
| cond := builder.NewCond() | |||
| if opts.UserId > 0 { | |||
| cond = cond.And(builder.Eq{"user_id": opts.UserId}) | |||
| } | |||
| if opts.OperateType != OperateTypeNull { | |||
| cond = cond.And(builder.Eq{"operate_type": opts.OperateType.Name()}) | |||
| } | |||
| cond = cond.And(builder.Eq{"reward_type": opts.RewardType.Name()}) | |||
| cond = cond.And(builder.Gt{"amount": 0}) | |||
| count, err := x.Where(cond).Count(&RewardOperateRecord{}) | |||
| if err != nil { | |||
| return nil, 0, err | |||
| } | |||
| err = x.Where(cond).Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).OrderBy(string(opts.OrderBy)).Find(&r) | |||
| if err != nil { | |||
| return nil, 0, err | |||
| } | |||
| return r, count, nil | |||
| } | |||
| @@ -29,7 +29,7 @@ func (r PeriodType) Name() string { | |||
| type RewardPeriodicTask struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| OperateRecordId string `xorm:"INDEX NOT NULL"` | |||
| OperateSerialNo string `xorm:"INDEX NOT NULL"` | |||
| DelaySeconds int64 | |||
| IntervalSeconds int64 | |||
| Amount int64 `xorm:"NOT NULL"` | |||
| @@ -45,6 +45,7 @@ type StartPeriodicTaskOpts struct { | |||
| SourceType SourceType | |||
| SourceId string | |||
| Remark string | |||
| Tittle string | |||
| TargetUserId int64 | |||
| RequestId string | |||
| OperateType RewardOperateType | |||
| @@ -76,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 record_id = ?", count*t.Amount, timeutil.TimeStampNow(), t.OperateRecordId) | |||
| _, err = sess.Exec("update reward_operate_record set amount = amount + ? ,updated_unix = ? where serial_no = ?", count*t.Amount, timeutil.TimeStampNow(), t.OperateSerialNo) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| @@ -88,7 +89,7 @@ func IncrRewardTaskSuccessCount(t RewardPeriodicTask, count int64, nextTime time | |||
| func GetPeriodicTaskBySourceIdAndType(sourceType SourceType, sourceId string, operateType RewardOperateType) (*RewardPeriodicTask, error) { | |||
| r := RewardPeriodicTask{} | |||
| _, err := x.SQL("select rpt.* from reward_periodic_task rpt "+ | |||
| "inner join reward_operate_record ror on rpt.operate_record_id = ror.record_id"+ | |||
| "inner join reward_operate_record ror on rpt.operate_serial_no = ror.serial_no"+ | |||
| " where ror.source_type = ? and source_id = ? and operate_type = ? ", sourceType.Name(), sourceId, operateType.Name()).Get(&r) | |||
| if err != nil { | |||
| return nil, err | |||
| @@ -96,7 +97,7 @@ func GetPeriodicTaskBySourceIdAndType(sourceType SourceType, sourceId string, op | |||
| return &r, nil | |||
| } | |||
| func StopPeriodicTask(taskId int64, operateRecordId string, stopTime time.Time) error { | |||
| func StopPeriodicTask(taskId int64, operateSerialNo string, stopTime time.Time) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| _, err := sess.Where("id = ? and status = ?", taskId, PeriodicTaskStatusRunning).Update(&RewardPeriodicTask{Status: PeriodicTaskStatusFinished, FinishedUnix: timeutil.TimeStamp(stopTime.Unix())}) | |||
| @@ -104,7 +105,7 @@ func StopPeriodicTask(taskId int64, operateRecordId string, stopTime time.Time) | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| _, err = sess.Where("record_id = ? and status = ?", operateRecordId, OperateStatusOperating).Update(&RewardOperateRecord{Status: OperateStatusSucceeded}) | |||
| _, err = sess.Where("serial_no = ? and status = ?", operateSerialNo, OperateStatusOperating).Update(&RewardOperateRecord{Status: OperateStatusSucceeded}) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| @@ -6,11 +6,12 @@ import ( | |||
| ) | |||
| type TaskAccomplishLog struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| LogId string `xorm:"INDEX NOT NULL"` | |||
| ConfigId int64 `xorm:"NOT NULL"` | |||
| TaskCode string `xorm:"NOT NULL"` | |||
| UserId int64 `xorm:"INDEX NOT NULL"` | |||
| ID int64 `xorm:"pk autoincr"` | |||
| LogId string `xorm:"INDEX NOT NULL"` | |||
| ConfigId int64 `xorm:"NOT NULL"` | |||
| TaskCode string `xorm:"NOT NULL"` | |||
| UserId int64 `xorm:"INDEX NOT NULL"` | |||
| ActionId int64 | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| } | |||
| @@ -4,36 +4,6 @@ import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| const ( | |||
| TaskTypeNewIssue = "NEW_ISSUE" | |||
| TaskTypeIssueChangeStatus = "ISSUE_CHANGE_STATUS" | |||
| TaskTypeCreateIssueComment = "CREATE_ISSUE_COMMENT" | |||
| TaskTypeNewPullRequest = "NEW_PULL_REQUEST" | |||
| TaskTypeRenameRepository = "RENAME_REPOSITORY" | |||
| TaskTypeAliasRepository = "ALIAS_REPOSITORY" | |||
| TaskTypeTransferRepository = "TRANSFER_REPOSITORY" | |||
| TaskTypeCreateRepository = "CREATE_REPOSITORY" | |||
| TaskTypeCreatePublicRepository = "CREATE_PUBLIC_REPOSITORY" | |||
| TaskTypeForkRepository = "FORK_REPOSITORY" | |||
| TaskTypePullRequestReview = "PULL_REQUEST_REVIEW" | |||
| TaskTypeCommentPull = "COMMENT_PULL" | |||
| TaskTypeApprovePullRequest = "APPROVE_PULL_REQUEST" | |||
| TaskTypeRejectPullRequest = "REJECT_PULL_REQUEST" | |||
| TaskTypeMergePullRequest = "MERGE_PULL_REQUEST" | |||
| TaskTypeSyncPushCommits = "SYNC_PUSH_COMMITS" | |||
| TaskTypeSyncCreateRef = "SYNC_CREATE_REF" | |||
| TaskTypeSyncDeleteRef = "SYNC_DELETE_REF" | |||
| TaskTypeBindWechat = "BIND_WECHAT" | |||
| TaskTypeUploadAttachment = "UPLOAD_ATTACHMENT" | |||
| TaskTypeCreateCloudbrainTask = "CREATE_CLOUDBRAIN_TASK" | |||
| TaskTypeDatasetRecommended = "DATASET_RECOMMENDED" | |||
| TaskTypeCreateModel = "CREATE_MODEL" | |||
| TaskTypeCreatePublicImage = "CREATE_PUBLIC_IMAGE" | |||
| TaskTypeImageRecommend = "IMAGE_RECOMMEND" | |||
| TaskTypeChangeUserAvatar = "CHANGE_USER_AVATAR" | |||
| TaskTypePushCommits = "PUSH_COMMITS" | |||
| ) | |||
| const ( | |||
| PeriodNotCycle = "NOT_CYCLE" | |||
| PeriodDaily = "DAILY" | |||
| @@ -1,6 +1,7 @@ | |||
| package wechat | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "code.gitea.io/gitea/modules/redis/redis_client" | |||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||
| @@ -72,6 +73,10 @@ func HandleSubscribeEvent(we WechatEvent) string { | |||
| jsonStr, _ := json.Marshal(qrCache) | |||
| redis_client.Setex(redis_key.WechatBindingUserIdKey(sceneStr), string(jsonStr), 60*time.Second) | |||
| } | |||
| notification.NotifyWechatBind(qrCache.UserId, we.FromUserName) | |||
| u, err := models.GetUserByID(qrCache.UserId) | |||
| if err == nil { | |||
| notification.NotifyWechatBind(u, we.FromUserName) | |||
| } | |||
| return BIND_REPLY_SUCCESS | |||
| } | |||
| @@ -212,7 +212,7 @@ func getQueryString(page int, size int, name string) string { | |||
| return fmt.Sprintf("pageIndex=%d&pageSize=%d&name=%s", page, size, name) | |||
| } | |||
| func CommitImage(jobID string, params models.CommitImageParams) error { | |||
| func CommitImage(jobID string, params models.CommitImageParams, doer *models.User) error { | |||
| imageTag := strings.TrimSpace(params.ImageTag) | |||
| dbImage, err := models.GetImageByTag(imageTag) | |||
| @@ -314,12 +314,12 @@ sendjob: | |||
| }) | |||
| if err == nil { | |||
| go updateImageStatus(image, isSetCreatedUnix, createTime) | |||
| notification.NotifyCreateImage(params.UID, image) | |||
| notification.NotifyCreateImage(doer, image) | |||
| } | |||
| return err | |||
| } | |||
| func CommitAdminImage(params models.CommitImageParams) error { | |||
| func CommitAdminImage(params models.CommitImageParams, doer *models.User) error { | |||
| imageTag := strings.TrimSpace(params.ImageTag) | |||
| exist, err := models.IsImageExist(imageTag) | |||
| @@ -357,7 +357,7 @@ func CommitAdminImage(params models.CommitImageParams) error { | |||
| return nil | |||
| }) | |||
| if err == nil { | |||
| notification.NotifyCreateImage(params.UID, image) | |||
| notification.NotifyCreateImage(doer, image) | |||
| } | |||
| return err | |||
| } | |||
| @@ -212,7 +212,7 @@ func registerRewardPeriodTask() { | |||
| RegisterTaskFatal("reward_period_task", &BaseConfig{ | |||
| Enabled: true, | |||
| RunAtStart: true, | |||
| Schedule: "@every 5m", | |||
| Schedule: "@every 1m", | |||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | |||
| reward.StartRewardTask() | |||
| return nil | |||
| @@ -5,6 +5,7 @@ | |||
| package action | |||
| import ( | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "encoding/json" | |||
| "fmt" | |||
| "path" | |||
| @@ -345,3 +346,105 @@ func (a *actionNotifier) NotifyOtherTask(doer *models.User, repo *models.Reposit | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| func (t *actionNotifier) NotifyWechatBind(user *models.User, wechatOpenId string) { | |||
| act := &models.Action{ | |||
| ActUserID: user.ID, | |||
| ActUser: user, | |||
| OpType: models.ActionBindWechat, | |||
| IsPrivate: true, | |||
| Content: wechatOpenId, | |||
| } | |||
| if err := models.NotifyWatchers(act); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| func (t *actionNotifier) NotifyDatasetRecommend(optUser *models.User, dataset *models.Dataset, action string) { | |||
| switch action { | |||
| case "recommend": | |||
| users, err := models.GetAllDatasetContributorByDatasetId(dataset.ID) | |||
| if err != nil { | |||
| return | |||
| } | |||
| var actions = make([]*models.Action, 0) | |||
| for _, user := range users { | |||
| actions = append(actions, &models.Action{ | |||
| OpType: models.ActionDatasetRecommended, | |||
| ActUserID: user.ID, | |||
| ActUser: user, | |||
| RepoID: dataset.RepoID, | |||
| Repo: dataset.Repo, | |||
| Content: fmt.Sprint(dataset.ID), | |||
| }) | |||
| } | |||
| if err := models.NotifyWatchers(actions...); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| } | |||
| func (t *actionNotifier) NotifyCreateImage(doer *models.User, image models.Image) { | |||
| act := &models.Action{ | |||
| ActUserID: doer.ID, | |||
| ActUser: doer, | |||
| OpType: models.ActionCreateImage, | |||
| IsPrivate: image.IsPrivate, | |||
| Content: fmt.Sprint(image.ID), | |||
| } | |||
| if err := models.NotifyWatchers(act); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| func (t *actionNotifier) NotifyImageRecommend(optUser *models.User, imageId int64, action string) { | |||
| image, err := models.GetImageByID(imageId) | |||
| if err != nil { | |||
| return | |||
| } | |||
| u, err := models.GetUserByID(image.UID) | |||
| if err != nil { | |||
| return | |||
| } | |||
| switch action { | |||
| case "recommend": | |||
| act := &models.Action{ | |||
| ActUserID: u.ID, | |||
| ActUser: u, | |||
| OpType: models.ActionImageRecommend, | |||
| IsPrivate: false, | |||
| Content: fmt.Sprint(imageId), | |||
| } | |||
| if err := models.NotifyWatchers(act); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| } | |||
| func (t *actionNotifier) NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) { | |||
| act := &models.Action{ | |||
| ActUserID: user.ID, | |||
| ActUser: user, | |||
| OpType: models.ActionChangeUserAvatar, | |||
| IsPrivate: true, | |||
| } | |||
| if err := models.NotifyWatchers(act); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| func (t *actionNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) { | |||
| act := &models.Action{ | |||
| ActUserID: pusher.ID, | |||
| ActUser: pusher, | |||
| OpType: models.ActionPushCommits, | |||
| RepoID: repo.ID, | |||
| Repo: repo, | |||
| RefName: refName, | |||
| IsPrivate: repo.IsPrivate, | |||
| Content: fmt.Sprintf("%s|%s", oldCommitID, newCommitID), | |||
| } | |||
| if err := models.NotifyWatchers(act); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| } | |||
| } | |||
| @@ -6,6 +6,7 @@ package base | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| ) | |||
| @@ -56,9 +57,9 @@ type Notifier interface { | |||
| NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) | |||
| NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType) | |||
| NotifyWechatBind(userId int64, wechatOpenId string) | |||
| NotifyWechatBind(user *models.User, wechatOpenId string) | |||
| NotifyDatasetRecommend(optUser *models.User, dataset *models.Dataset, action string) | |||
| NotifyCreateImage(optUserId int64, image models.Image) | |||
| NotifyCreateImage(doer *models.User, image models.Image) | |||
| NotifyImageRecommend(optUser *models.User, imageId int64, action string) | |||
| NotifyChangeUserAvatar(user *models.User) | |||
| NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) | |||
| } | |||
| @@ -6,6 +6,7 @@ package base | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| ) | |||
| @@ -159,18 +160,19 @@ func (*NullNotifier) NotifyOtherTask(doer *models.User, repo *models.Repository, | |||
| } | |||
| func (*NullNotifier) NotifyWechatBind(userId int64, wechatOpenId string) { | |||
| func (*NullNotifier) NotifyWechatBind(user *models.User, wechatOpenId string) { | |||
| } | |||
| func (*NullNotifier) NotifyDatasetRecommend(optUser *models.User, dataset *models.Dataset, action string) { | |||
| } | |||
| func (*NullNotifier) NotifyCreateImage(optUserId int64, image models.Image) { | |||
| func (*NullNotifier) NotifyCreateImage(doer *models.User, image models.Image) { | |||
| } | |||
| func (*NullNotifier) NotifyImageRecommend(optUser *models.User, imageId int64, action string) { | |||
| } | |||
| func (*NullNotifier) NotifyChangeUserAvatar(user *models.User) { | |||
| func (*NullNotifier) NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) { | |||
| } | |||
| @@ -6,11 +6,11 @@ package notification | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/notification/action" | |||
| "code.gitea.io/gitea/modules/notification/base" | |||
| "code.gitea.io/gitea/modules/notification/indexer" | |||
| "code.gitea.io/gitea/modules/notification/mail" | |||
| "code.gitea.io/gitea/modules/notification/task" | |||
| "code.gitea.io/gitea/modules/notification/ui" | |||
| "code.gitea.io/gitea/modules/notification/webhook" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| @@ -36,7 +36,6 @@ func NewContext() { | |||
| RegisterNotifier(indexer.NewNotifier()) | |||
| RegisterNotifier(webhook.NewNotifier()) | |||
| RegisterNotifier(action.NewNotifier()) | |||
| RegisterNotifier(task.NewNotifier()) | |||
| } | |||
| // NotifyUploadAttachment notifies attachment upload message to notifiers | |||
| @@ -273,9 +272,9 @@ func NotifySyncDeleteRef(pusher *models.User, repo *models.Repository, refType, | |||
| } | |||
| // NotifyWechatBind notifies wechat bind | |||
| func NotifyWechatBind(userId int64, wechatOpenId string) { | |||
| func NotifyWechatBind(user *models.User, wechatOpenId string) { | |||
| for _, notifier := range notifiers { | |||
| notifier.NotifyWechatBind(userId, wechatOpenId) | |||
| notifier.NotifyWechatBind(user, wechatOpenId) | |||
| } | |||
| } | |||
| @@ -287,9 +286,9 @@ func NotifyDatasetRecommend(optUser *models.User, dataset *models.Dataset, actio | |||
| } | |||
| // NotifyDatasetRecommend | |||
| func NotifyCreateImage(optUserId int64, image models.Image) { | |||
| func NotifyCreateImage(doer *models.User, image models.Image) { | |||
| for _, notifier := range notifiers { | |||
| notifier.NotifyCreateImage(optUserId, image) | |||
| notifier.NotifyCreateImage(doer, image) | |||
| } | |||
| } | |||
| @@ -301,8 +300,8 @@ func NotifyImageRecommend(optUser *models.User, imageId int64, action string) { | |||
| } | |||
| // NotifyDatasetRecommend | |||
| func NotifyChangeUserAvatar(user *models.User) { | |||
| func NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) { | |||
| for _, notifier := range notifiers { | |||
| notifier.NotifyChangeUserAvatar(user) | |||
| notifier.NotifyChangeUserAvatar(user, form) | |||
| } | |||
| } | |||
| @@ -1,157 +0,0 @@ | |||
| package task | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/notification/base" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| "code.gitea.io/gitea/services/task" | |||
| "strings" | |||
| ) | |||
| type taskNotifier struct { | |||
| base.NullNotifier | |||
| } | |||
| var ( | |||
| _ base.Notifier = &taskNotifier{} | |||
| ) | |||
| // NewNotifier create a new actionNotifier notifier | |||
| func NewNotifier() base.Notifier { | |||
| return &taskNotifier{} | |||
| } | |||
| func (t *taskNotifier) NotifyNewIssue(issue *models.Issue) { | |||
| task.Accomplish(issue.Poster.ID, models.TaskTypeNewIssue) | |||
| } | |||
| // NotifyIssueChangeStatus notifies close or reopen issue to notifiers | |||
| func (t *taskNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, closeOrReopen bool) { | |||
| task.Accomplish(doer.ID, models.TaskTypeIssueChangeStatus) | |||
| } | |||
| // NotifyCreateIssueComment notifies comment on an issue to notifiers | |||
| func (t *taskNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository, | |||
| issue *models.Issue, comment *models.Comment) { | |||
| task.Accomplish(doer.ID, models.TaskTypeCreateIssueComment) | |||
| } | |||
| func (t *taskNotifier) NotifyNewPullRequest(pull *models.PullRequest) { | |||
| task.Accomplish(pull.Issue.Poster.ID, models.TaskTypeNewPullRequest) | |||
| } | |||
| func (t *taskNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string) { | |||
| task.Accomplish(doer.ID, models.TaskTypeRenameRepository) | |||
| } | |||
| func (t *taskNotifier) NotifyAliasRepository(doer *models.User, repo *models.Repository, oldAlias string) { | |||
| task.Accomplish(doer.ID, models.TaskTypeAliasRepository) | |||
| } | |||
| func (t *taskNotifier) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) { | |||
| task.Accomplish(doer.ID, models.TaskTypeTransferRepository) | |||
| } | |||
| func (t *taskNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) { | |||
| if !repo.IsPrivate { | |||
| task.Accomplish(doer.ID, models.TaskTypeCreatePublicRepository) | |||
| } | |||
| } | |||
| func (t *taskNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) { | |||
| task.Accomplish(doer.ID, models.TaskTypeForkRepository) | |||
| } | |||
| func (t *taskNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) { | |||
| for _, lines := range review.CodeComments { | |||
| for _, comments := range lines { | |||
| for _, _ = range comments { | |||
| task.Accomplish(review.Reviewer.ID, models.TaskTypePullRequestReview) | |||
| } | |||
| } | |||
| } | |||
| if review.Type != models.ReviewTypeComment || strings.TrimSpace(comment.Content) != "" { | |||
| switch review.Type { | |||
| case models.ReviewTypeApprove: | |||
| task.Accomplish(review.Reviewer.ID, models.TaskTypeApprovePullRequest) | |||
| case models.ReviewTypeReject: | |||
| task.Accomplish(review.Reviewer.ID, models.TaskTypeRejectPullRequest) | |||
| default: | |||
| task.Accomplish(review.Reviewer.ID, models.TaskTypeCommentPull) | |||
| } | |||
| } | |||
| } | |||
| func (t *taskNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) { | |||
| task.Accomplish(doer.ID, models.TaskTypeMergePullRequest) | |||
| } | |||
| func (t *taskNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) { | |||
| task.Accomplish(repo.OwnerID, models.TaskTypeSyncPushCommits) | |||
| } | |||
| func (t *taskNotifier) NotifySyncCreateRef(doer *models.User, repo *models.Repository, refType, refFullName string) { | |||
| task.Accomplish(repo.OwnerID, models.TaskTypeSyncCreateRef) | |||
| } | |||
| func (t *taskNotifier) NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) { | |||
| task.Accomplish(repo.OwnerID, models.TaskTypeSyncDeleteRef) | |||
| } | |||
| func (t *taskNotifier) NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType) { | |||
| switch optype { | |||
| case models.ActionUploadAttachment: | |||
| task.Accomplish(doer.ID, models.TaskTypeUploadAttachment) | |||
| case models.ActionCreateDebugGPUTask, | |||
| models.ActionCreateDebugNPUTask, | |||
| models.ActionCreateTrainTask, | |||
| models.ActionCreateInferenceTask, | |||
| models.ActionCreateBenchMarkTask, | |||
| models.ActionCreateGPUTrainTask: | |||
| task.Accomplish(doer.ID, models.TaskTypeCreateCloudbrainTask) | |||
| case models.ActionCreateNewModelTask: | |||
| task.Accomplish(doer.ID, models.TaskTypeCreateModel) | |||
| } | |||
| return | |||
| } | |||
| func (t *taskNotifier) NotifyWechatBind(userId int64, wechatOpenId string) { | |||
| task.Accomplish(userId, models.TaskTypeBindWechat) | |||
| } | |||
| func (t *taskNotifier) NotifyDatasetRecommend(optUser *models.User, dataset *models.Dataset, action string) { | |||
| switch action { | |||
| case "recommend": | |||
| userIds, err := models.GetAllUserIdByDatasetId(dataset.ID) | |||
| if err != nil { | |||
| return | |||
| } | |||
| for _, userId := range userIds { | |||
| task.Accomplish(userId, models.TaskTypeDatasetRecommended) | |||
| } | |||
| } | |||
| } | |||
| func (t *taskNotifier) NotifyCreateImage(optUserId int64, image models.Image) { | |||
| if !image.IsPrivate { | |||
| task.Accomplish(optUserId, models.TaskTypeCreatePublicImage) | |||
| } | |||
| } | |||
| func (t *taskNotifier) NotifyImageRecommend(optUser *models.User, imageId int64, action string) { | |||
| switch action { | |||
| case "recommend": | |||
| task.Accomplish(optUser.ID, models.TaskTypeImageRecommend) | |||
| } | |||
| } | |||
| func (t *taskNotifier) NotifyChangeUserAvatar(user *models.User) { | |||
| task.Accomplish(user.ID, models.TaskTypeChangeUserAvatar) | |||
| } | |||
| func (t *taskNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *repository.PushCommits) { | |||
| task.Accomplish(pusher.ID, models.TaskTypePushCommits) | |||
| } | |||
| @@ -99,11 +99,11 @@ func IncrBy(key string, n int64) (int64, error) { | |||
| } | |||
| func Expire(key string, expireSeconds int64) error { | |||
| func Expire(key string, expireTime time.Duration) error { | |||
| redisClient := labelmsg.Get() | |||
| defer redisClient.Close() | |||
| _, err := redisClient.Do("EXPIRE", key, expireSeconds) | |||
| _, err := redisClient.Do("EXPIRE", key, int64(expireTime.Seconds())) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| @@ -1,6 +1,8 @@ | |||
| package redis_key | |||
| import "fmt" | |||
| import ( | |||
| "fmt" | |||
| ) | |||
| const REWARD_REDIS_PREFIX = "reward" | |||
| @@ -11,6 +13,7 @@ func RewardOperateLock(requestId string, sourceType string, operateType string) | |||
| func RewardOperateNotification() string { | |||
| return KeyJoin(REWARD_REDIS_PREFIX, "operate", "notification") | |||
| } | |||
| func RewardTaskRunningLock(taskId int64) string { | |||
| return KeyJoin(REWARD_REDIS_PREFIX, "periodic_task", fmt.Sprint(taskId), "lock") | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| package redis_key | |||
| import "time" | |||
| const SERIAL_REDIS_PREFIX = "serial" | |||
| func RewardSerialCounter(now time.Time) string { | |||
| h := now.Format("200601021504") | |||
| return KeyJoin(SERIAL_REDIS_PREFIX, "reward_operate", h, "counter") | |||
| } | |||
| @@ -232,7 +232,7 @@ var ( | |||
| TimeoutStep: 10 * time.Second, | |||
| MaxTimeout: 60 * time.Second, | |||
| EventSourceUpdateTime: 10 * time.Second, | |||
| RewardNotifyUpdateTime: 3 * time.Second, | |||
| RewardNotifyUpdateTime: 2 * time.Second, | |||
| }, | |||
| Admin: struct { | |||
| UserPagingNum int | |||
| @@ -549,7 +549,9 @@ var ( | |||
| WechatAuthSwitch bool | |||
| //point config | |||
| CloudBrainTaskPointPaySwitch bool | |||
| CloudBrainPaySwitch bool | |||
| CloudBrainPayDelay time.Duration | |||
| CloudBrainPayInterval time.Duration | |||
| //nginx proxy | |||
| PROXYURL string | |||
| @@ -1380,7 +1382,9 @@ func NewContext() { | |||
| WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(false) | |||
| sec = Cfg.Section("point") | |||
| CloudBrainTaskPointPaySwitch = sec.Key("CLOUDBRAIN_PAY_SWITCH").MustBool(false) | |||
| CloudBrainPaySwitch = sec.Key("CLOUDBRAIN_PAY_SWITCH").MustBool(false) | |||
| CloudBrainPayDelay = sec.Key("CLOUDBRAIN_PAY_DELAY").MustDuration(30 * time.Minute) | |||
| CloudBrainPayInterval = sec.Key("CLOUDBRAIN_PAY_INTERVAL").MustDuration(60 * time.Minute) | |||
| SetRadarMapConfig() | |||
| @@ -233,7 +233,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, jobType, resourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, jobType, resourceSpecId) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("point balance not enough", tpl, &form) | |||
| ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tpl, &form) | |||
| return | |||
| } | |||
| @@ -319,7 +319,7 @@ func CloudBrainRestart(ctx *context.Context) { | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, task.JobType, task.ResourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, task.JobType, task.ResourceSpecId) | |||
| resultCode = "-1" | |||
| errorMsg = "insufficient points balance" | |||
| errorMsg = models.ErrInsufficientPointsBalance{}.Error() | |||
| break | |||
| } | |||
| @@ -737,7 +737,7 @@ func CloudBrainAdminCommitImage(ctx *context.Context, form auth.CommitAdminImage | |||
| UID: ctx.User.ID, | |||
| Type: models.GetRecommondType(form.IsRecommend), | |||
| Place: form.Place, | |||
| }) | |||
| }, ctx.User) | |||
| if err != nil { | |||
| log.Error("CommitImagefailed") | |||
| if models.IsErrImageTagExist(err) { | |||
| @@ -784,7 +784,7 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain | |||
| CloudBrainType: form.Type, | |||
| Topics: validTopics, | |||
| UID: ctx.User.ID, | |||
| }) | |||
| }, ctx.User) | |||
| if err != nil { | |||
| log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"]) | |||
| if models.IsErrImageTagExist(err) { | |||
| @@ -1862,7 +1862,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("point balance not enough", tplCloudBrainBenchmarkNew, &form) | |||
| ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplCloudBrainBenchmarkNew, &form) | |||
| return | |||
| } | |||
| @@ -2024,7 +2024,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, jobType, resourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, jobType, resourceSpecId) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("point balance not enough", tpl, &form) | |||
| ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tpl, &form) | |||
| return | |||
| } | |||
| @@ -210,7 +210,7 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, string(models.JobTypeDebug), resourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("point balance not enough", tplModelArtsNotebookNew, &form) | |||
| ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplModelArtsNotebookNew, &form) | |||
| return | |||
| } | |||
| count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID) | |||
| @@ -429,7 +429,7 @@ func NotebookManage(ctx *context.Context) { | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, task.JobType, task.ResourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, task.JobType, task.ResourceSpecId) | |||
| resultCode = "-1" | |||
| errorMsg = "point balance not enough" | |||
| errorMsg = models.ErrInsufficientPointsBalance{}.Error() | |||
| break | |||
| return | |||
| } | |||
| @@ -1005,7 +1005,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, string(models.JobTypeTrain), resourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("point balance not enough", tplModelArtsTrainJobNew, &form) | |||
| ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplModelArtsTrainJobNew, &form) | |||
| return | |||
| } | |||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | |||
| @@ -1854,7 +1854,7 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference | |||
| if !reward.IsPointBalanceEnough(ctx.User.ID, string(models.JobTypeInference), resourceSpecId) { | |||
| log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("point balance not enough", tplModelArtsInferenceJobNew, &form) | |||
| ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) | |||
| @@ -1,8 +1,10 @@ | |||
| package point | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/routers/response" | |||
| "code.gitea.io/gitea/services/reward" | |||
| "code.gitea.io/gitea/services/reward/point/account" | |||
| "net/http" | |||
| ) | |||
| @@ -29,3 +31,47 @@ func GetPointAccount(ctx *context.Context) { | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(res)) | |||
| } | |||
| func GetPointRecordList(ctx *context.Context) { | |||
| operateType := ctx.Query("operate") | |||
| page := ctx.QueryInt("page") | |||
| var orderBy models.RewardOperateOrderBy | |||
| switch ctx.Query("sort") { | |||
| default: | |||
| orderBy = models.RewardOrderByID | |||
| } | |||
| t := models.GetRewardOperateTypeInstance(operateType) | |||
| if t == "" { | |||
| ctx.JSON(http.StatusOK, response.ServerError("param error")) | |||
| return | |||
| } | |||
| r, err := reward.GetRewardRecordList(models.RewardRecordListOpts{ | |||
| ListOptions: models.ListOptions{PageSize: 20, Page: page}, | |||
| UserId: ctx.User.ID, | |||
| OperateType: t, | |||
| RewardType: models.RewardTypePoint, | |||
| OrderBy: orderBy, | |||
| }) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | |||
| return | |||
| } | |||
| func OperatePointAccountBalance(ctx *context.Context, req models.AdminRewardOperateReq) { | |||
| req.RewardType = models.RewardTypePoint | |||
| if req.OperateType.Name() == "" { | |||
| ctx.JSON(http.StatusOK, "param error") | |||
| return | |||
| } | |||
| err := reward.AdminBalanceOperate(req, ctx.User) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
| return | |||
| } | |||
| ctx.JSON(http.StatusOK, response.Success()) | |||
| } | |||
| @@ -324,6 +324,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/", routers.Home) | |||
| m.Get("/dashboard", routers.Dashboard) | |||
| go routers.SocketManager.Run() | |||
| go task.RunTask() | |||
| m.Get("/action/notification", routers.ActionNotification) | |||
| m.Get("/reward/notification", routers.ActionNotification) | |||
| m.Get("/recommend/org", routers.RecommendOrgFromPromote) | |||
| @@ -594,6 +595,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/reward/point", func() { | |||
| m.Get("/limiter/list", point.GetPointLimitConfigList) | |||
| m.Post("/limiter/add", bindIgnErr(models.LimitConfigVO{}), point.AddPointLimitConfig) | |||
| m.Post("/operate", binding.Bind(models.AdminRewardOperateReq{}), point.OperatePointAccountBalance) | |||
| }) | |||
| m.Group("/task/config", func() { | |||
| @@ -601,6 +603,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/add", bindIgnErr(models.TaskConfigWithLimit{}), task.AddTaskConfig) | |||
| m.Post("/add/batch", bindIgnErr(models.BatchLimitConfigVO{}), task.BatchAddTaskConfig) | |||
| }) | |||
| }, adminReq) | |||
| // ***** END: Admin ***** | |||
| @@ -1330,6 +1333,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/reward/point", func() { | |||
| m.Get("/account", point.GetPointAccount) | |||
| m.Get("/record/list", point.GetPointRecordList) | |||
| }, reqSignIn) | |||
| if setting.API.EnableSwagger { | |||
| @@ -0,0 +1,15 @@ | |||
| package task | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/services/task" | |||
| ) | |||
| func RunTask() { | |||
| for { | |||
| select { | |||
| case action := <-models.ActionChan4Task: | |||
| task.Accomplish(action) | |||
| } | |||
| } | |||
| } | |||
| @@ -166,7 +166,7 @@ func AvatarPost(ctx *context.Context, form auth.AvatarForm) { | |||
| if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil { | |||
| ctx.Flash.Error(err.Error()) | |||
| } else { | |||
| notification.NotifyChangeUserAvatar(ctx.User) | |||
| notification.NotifyChangeUserAvatar(ctx.User, form) | |||
| ctx.Flash.Success(ctx.Tr("settings.update_avatar_success")) | |||
| } | |||
| @@ -0,0 +1,50 @@ | |||
| package reward | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/util" | |||
| "code.gitea.io/gitea/services/reward/limiter" | |||
| ) | |||
| func AdminBalanceOperate(req models.AdminRewardOperateReq, doer *models.User) error { | |||
| logId := util.UUID() | |||
| _, err := models.InsertRewardAdminLog(&models.RewardAdminLog{ | |||
| LogId: logId, | |||
| Amount: req.Amount, | |||
| RewardType: req.RewardType.Name(), | |||
| TargetUserId: req.TargetUserId, | |||
| CreatorId: doer.ID, | |||
| CreatorName: doer.Name, | |||
| Remark: req.Remark, | |||
| Status: models.RewardAdminLogProcessing, | |||
| }) | |||
| if err != nil { | |||
| log.Error("AdminBalanceOperate InsertRewardAdminLog error.%v", err) | |||
| return err | |||
| } | |||
| //reward | |||
| err = Operate(&models.RewardOperateContext{ | |||
| SourceType: models.SourceTypeAdminOperate, | |||
| SourceId: logId, | |||
| Tittle: "管理员操作", | |||
| Reward: models.Reward{ | |||
| Amount: req.Amount, | |||
| Type: req.RewardType, | |||
| }, | |||
| TargetUserId: req.TargetUserId, | |||
| RequestId: logId, | |||
| OperateType: req.OperateType, | |||
| Remark: req.Remark, | |||
| RejectPolicy: limiter.JustReject, | |||
| }) | |||
| if err != nil { | |||
| log.Error("AdminBalanceOperate operate error.%v", err) | |||
| models.UpdateRewardAdminLogStatus(logId, models.RewardAdminLogProcessing, models.RewardAdminLogFailed) | |||
| return err | |||
| } | |||
| models.UpdateRewardAdminLogStatus(logId, models.RewardAdminLogProcessing, models.RewardAdminLogSuccess) | |||
| return nil | |||
| } | |||
| @@ -15,9 +15,11 @@ var ( | |||
| TrainResourceSpecs *models.ResourceSpecs | |||
| ) | |||
| const RUN_CLOUDBRAIN_TASK_TITTLE = "运行云脑任务" | |||
| //IsPointBalanceEnough check whether the user's point balance is bigger than task unit price | |||
| func IsPointBalanceEnough(targetUserId int64, jobType string, resourceSpecId int) bool { | |||
| if !setting.CloudBrainTaskPointPaySwitch { | |||
| if !setting.CloudBrainPaySwitch { | |||
| return true | |||
| } | |||
| spec := getResourceSpec(jobType, resourceSpecId) | |||
| @@ -33,7 +35,7 @@ func IsPointBalanceEnough(targetUserId int64, jobType string, resourceSpecId int | |||
| } | |||
| func StartCloudBrainPointDeductTask(task models.Cloudbrain) { | |||
| if !setting.CloudBrainTaskPointPaySwitch { | |||
| if !setting.CloudBrainPaySwitch { | |||
| return | |||
| } | |||
| @@ -48,11 +50,12 @@ func StartCloudBrainPointDeductTask(task models.Cloudbrain) { | |||
| TargetUserId: task.UserID, | |||
| RequestId: getCloudBrainPointTaskSourceId(task), | |||
| OperateType: models.OperateTypeDecrease, | |||
| Delay: 30 * time.Minute, | |||
| Interval: 60 * time.Minute, | |||
| Delay: setting.CloudBrainPayDelay, | |||
| Interval: setting.CloudBrainPayInterval, | |||
| UnitAmount: spec.UnitPrice, | |||
| RewardType: models.RewardTypePoint, | |||
| StartTime: time.Unix(int64(task.StartTime), 0), | |||
| Tittle: RUN_CLOUDBRAIN_TASK_TITTLE, | |||
| }) | |||
| } | |||
| @@ -61,7 +64,7 @@ func StopCloudBrainPointDeductTask(task models.Cloudbrain) { | |||
| } | |||
| func getCloudBrainPointTaskSourceId(task models.Cloudbrain) string { | |||
| return models.SourceTypeRunCloudbrainTask.Name() + "_" + task.JobType + "_" + fmt.Sprint(task.Type) + "_" + fmt.Sprint(task.ID) | |||
| return fmt.Sprint(task.ID) | |||
| } | |||
| func getResourceSpec(jobType string, resourceSpecId int) *models.ResourceSpec { | |||
| @@ -100,11 +103,11 @@ func StartCloudbrainPointDeductTask() { | |||
| }() | |||
| log.Debug("try to run CloudbrainPointDeductTask") | |||
| end := time.Now() | |||
| start := end.Add(5 * time.Minute) | |||
| start := end.Add(-5 * 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 | |||
| start = end.Add(1 * time.Hour) | |||
| start = end.Add(-1 * time.Hour) | |||
| firstTimeFlag = false | |||
| } | |||
| @@ -12,14 +12,6 @@ import ( | |||
| "time" | |||
| ) | |||
| type limiterRejectPolicy string | |||
| const ( | |||
| JustReject limiterRejectPolicy = "JUST_REJECT" | |||
| PermittedOnce limiterRejectPolicy = "PERMITTED_ONCE" | |||
| FillUp limiterRejectPolicy = "FillUp" | |||
| ) | |||
| type limiterRunner struct { | |||
| limiters []models.LimitConfig | |||
| index int | |||
| @@ -27,7 +19,7 @@ type limiterRunner struct { | |||
| amount int64 | |||
| limitCode string | |||
| limitType models.LimitType | |||
| rejectPolicy limiterRejectPolicy | |||
| rejectPolicy models.LimiterRejectPolicy | |||
| resultMap map[int]limitResult | |||
| minRealAmount int64 | |||
| } | |||
| @@ -46,7 +38,7 @@ func newLimitResult(isLoss bool, planAmount int64, realAmount int64) limitResult | |||
| } | |||
| } | |||
| func newLimiterRunner(limitCode string, limitType models.LimitType, userId, amount int64, policy limiterRejectPolicy) *limiterRunner { | |||
| func newLimiterRunner(limitCode string, limitType models.LimitType, userId, amount int64, policy models.LimiterRejectPolicy) *limiterRunner { | |||
| return &limiterRunner{ | |||
| userId: userId, | |||
| amount: amount, | |||
| @@ -149,7 +141,7 @@ func (l *limiterRunner) limit(r models.LimitConfig) error { | |||
| usedNum, err = redis_client.IncrBy(redisKey, n) | |||
| } | |||
| if p != nil { | |||
| redis_client.Expire(redisKey, int64(p.LeftTime.Seconds())) | |||
| redis_client.Expire(redisKey, p.LeftTime) | |||
| } | |||
| } | |||
| if usedNum > r.LimitNum { | |||
| @@ -158,16 +150,16 @@ func (l *limiterRunner) limit(r models.LimitConfig) error { | |||
| return errors.New(fmt.Sprintf("%s:over limit", r.Tittle)) | |||
| } | |||
| switch l.rejectPolicy { | |||
| case FillUp: | |||
| case models.FillUp: | |||
| exceed := usedNum - r.LimitNum | |||
| realAmount := l.amount - exceed | |||
| redis_client.IncrBy(redisKey, -1*exceed) | |||
| l.resultMap[l.index] = newLimitResult(true, l.amount, realAmount) | |||
| return nil | |||
| case JustReject: | |||
| case models.JustReject: | |||
| redis_client.IncrBy(redisKey, -1*l.amount) | |||
| return errors.New(fmt.Sprintf("%s:over limit", r.Tittle)) | |||
| case PermittedOnce: | |||
| case models.PermittedOnce: | |||
| l.resultMap[l.index] = newLimitResult(false, l.amount, l.amount) | |||
| return nil | |||
| } | |||
| @@ -200,8 +192,11 @@ func (l *limiterRunner) countInPeriod(r models.LimitConfig, p *models.PeriodResu | |||
| } | |||
| } | |||
| func CheckLimitWithFillUp(limitCode string, limitType models.LimitType, userId, amount int64) (int64, error) { | |||
| r := newLimiterRunner(limitCode, limitType, userId, amount, FillUp) | |||
| func CheckLimit(limitCode string, limitType models.LimitType, userId, amount int64, rejectPolicy models.LimiterRejectPolicy) (int64, error) { | |||
| if rejectPolicy == "" { | |||
| rejectPolicy = models.JustReject | |||
| } | |||
| r := newLimiterRunner(limitCode, limitType, userId, amount, rejectPolicy) | |||
| err := r.Run() | |||
| if err != nil { | |||
| return 0, err | |||
| @@ -209,18 +204,6 @@ func CheckLimitWithFillUp(limitCode string, limitType models.LimitType, userId, | |||
| return r.minRealAmount, nil | |||
| } | |||
| func CheckLimitWithPermittedOnce(limitCode string, limitType models.LimitType, userId, amount int64) error { | |||
| r := newLimiterRunner(limitCode, limitType, userId, amount, PermittedOnce) | |||
| err := r.Run() | |||
| return err | |||
| } | |||
| func CheckLimit(limitCode string, limitType models.LimitType, userId, amount int64) error { | |||
| r := newLimiterRunner(limitCode, limitType, userId, amount, JustReject) | |||
| err := r.Run() | |||
| return err | |||
| } | |||
| func GetLimiters(limitCode string, limitType models.LimitType) ([]models.LimitConfig, error) { | |||
| limiters, err := GetLimitersByLimitType(limitType) | |||
| if err != nil { | |||
| @@ -5,7 +5,6 @@ import ( | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||
| "code.gitea.io/gitea/modules/redis/redis_lock" | |||
| "code.gitea.io/gitea/modules/util" | |||
| "code.gitea.io/gitea/services/reward/point" | |||
| "errors" | |||
| "fmt" | |||
| @@ -69,7 +68,7 @@ func Operate(ctx *models.RewardOperateContext) error { | |||
| } | |||
| //new reward operate record | |||
| recordId, err := initAwardOperateRecord(ctx) | |||
| recordId, err := initRewardOperateRecord(ctx) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| @@ -110,9 +109,12 @@ func isHandled(sourceType string, requestId string, operateType string) (bool, e | |||
| } | |||
| func initAwardOperateRecord(ctx *models.RewardOperateContext) (string, error) { | |||
| func initRewardOperateRecord(ctx *models.RewardOperateContext) (string, error) { | |||
| sn, err := generateOperateSerialNo(ctx.OperateType, ctx.Reward.Type) | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| record := &models.RewardOperateRecord{ | |||
| RecordId: util.UUID(), | |||
| UserId: ctx.TargetUserId, | |||
| Amount: ctx.Reward.Amount, | |||
| RewardType: ctx.Reward.Type.Name(), | |||
| @@ -122,17 +124,22 @@ func initAwardOperateRecord(ctx *models.RewardOperateContext) (string, error) { | |||
| OperateType: ctx.OperateType.Name(), | |||
| Status: models.OperateStatusOperating, | |||
| Remark: ctx.Remark, | |||
| Tittle: ctx.Tittle, | |||
| SerialNo: sn, | |||
| } | |||
| _, err := models.InsertAwardOperateRecord(record) | |||
| _, err = models.InsertRewardOperateRecord(record) | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| return record.RecordId, nil | |||
| return record.SerialNo, nil | |||
| } | |||
| func createPeriodicRewardOperateRecord(ctx *models.StartPeriodicTaskOpts) (string, error) { | |||
| sn, err := generateOperateSerialNo(ctx.OperateType, ctx.RewardType) | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| record := &models.RewardOperateRecord{ | |||
| RecordId: util.UUID(), | |||
| UserId: ctx.TargetUserId, | |||
| Amount: 0, | |||
| RewardType: ctx.RewardType.Name(), | |||
| @@ -142,12 +149,14 @@ func createPeriodicRewardOperateRecord(ctx *models.StartPeriodicTaskOpts) (strin | |||
| OperateType: ctx.OperateType.Name(), | |||
| Status: models.OperateStatusOperating, | |||
| Remark: ctx.Remark, | |||
| Tittle: ctx.Tittle, | |||
| SerialNo: sn, | |||
| } | |||
| _, err := models.InsertAwardOperateRecord(record) | |||
| _, err = models.InsertRewardOperateRecord(record) | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| return record.RecordId, nil | |||
| return record.SerialNo, nil | |||
| } | |||
| func updateAwardOperateRecordStatus(sourceType, requestId, oldStatus, newStatus string) error { | |||
| @@ -230,5 +239,30 @@ func StopPeriodicTask(sourceType models.SourceType, sourceId string, operateType | |||
| } | |||
| now := time.Now() | |||
| RunRewardTask(*task, now) | |||
| return models.StopPeriodicTask(task.ID, task.OperateRecordId, now) | |||
| return models.StopPeriodicTask(task.ID, task.OperateSerialNo, now) | |||
| } | |||
| func generateOperateSerialNo(operateType models.RewardOperateType, rewardType models.RewardType) (string, error) { | |||
| s, err := GetSerialNoByRedis() | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| switch operateType { | |||
| case models.OperateTypeIncrease: | |||
| s += "1" | |||
| case models.OperateTypeDecrease: | |||
| s += "2" | |||
| default: | |||
| s += "9" | |||
| } | |||
| switch rewardType { | |||
| case models.RewardTypePoint: | |||
| s += "1" | |||
| default: | |||
| s += "9" | |||
| } | |||
| return s, nil | |||
| } | |||
| @@ -15,7 +15,7 @@ func NewRewardPeriodicTask(operateRecordId string, opts *models.StartPeriodicTas | |||
| task.DelaySeconds = int64(opts.Delay.Seconds()) | |||
| task.IntervalSeconds = int64(opts.Interval.Seconds()) | |||
| task.Amount = opts.UnitAmount | |||
| task.OperateRecordId = operateRecordId | |||
| task.OperateSerialNo = operateRecordId | |||
| task.Status = models.PeriodicTaskStatusRunning | |||
| task.NextExecuteTime = timeutil.TimeStamp(opts.StartTime.Add(opts.Delay).Unix()) | |||
| @@ -54,9 +54,9 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) { | |||
| return | |||
| } | |||
| defer lock.UnLock() | |||
| record, err := models.GetPointOperateRecordByRecordId(t.OperateRecordId) | |||
| record, err := models.GetPointOperateRecordBySerialNo(t.OperateSerialNo) | |||
| if err != nil { | |||
| log.Error("RunRewardTask. GetPointOperateRecordByRecordId error. %v", err) | |||
| log.Error("RunRewardTask. GetPointOperateRecordBySerialNo error. %v", err) | |||
| return | |||
| } | |||
| if record.Status != models.OperateStatusOperating { | |||
| @@ -75,7 +75,7 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) { | |||
| } | |||
| err = operator.Operate(&models.RewardOperateContext{ | |||
| SourceType: models.SourceTypeRunCloudbrainTask, | |||
| SourceId: t.OperateRecordId, | |||
| SourceId: t.OperateSerialNo, | |||
| Reward: models.Reward{ | |||
| Amount: n * t.Amount, | |||
| Type: models.GetRewardTypeInstance(record.RewardType), | |||
| @@ -18,7 +18,7 @@ type PointOperator struct { | |||
| } | |||
| func (operator *PointOperator) IsLimited(ctx *models.RewardOperateContext) bool { | |||
| realAmount, err := limiter.CheckLimitWithFillUp(ctx.SourceType.Name(), models.LimitTypeRewardPoint, ctx.TargetUserId, ctx.Reward.Amount) | |||
| realAmount, err := limiter.CheckLimit(ctx.SourceType.Name(), models.LimitTypeRewardPoint, ctx.TargetUserId, ctx.Reward.Amount, ctx.RejectPolicy) | |||
| if err != nil { | |||
| return true | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| package reward | |||
| import "code.gitea.io/gitea/models" | |||
| type RecordResponse struct { | |||
| Records []models.RewardOperateRecordShow | |||
| Total int64 | |||
| } | |||
| func GetRewardRecordList(opts models.RewardRecordListOpts) (*RecordResponse, error) { | |||
| l, n, err := models.GetRewardRecordList(opts) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| r := make([]models.RewardOperateRecordShow, 0) | |||
| for _, v := range l { | |||
| r = append(r, v.ToShow()) | |||
| } | |||
| return &RecordResponse{Records: r, Total: n}, nil | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package reward | |||
| import ( | |||
| "code.gitea.io/gitea/modules/redis/redis_client" | |||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||
| "fmt" | |||
| "math/rand" | |||
| "time" | |||
| ) | |||
| func GetSerialNoByRedis() (string, error) { | |||
| now := time.Now() | |||
| n, err := redis_client.IncrBy(redis_key.RewardSerialCounter(now), 1) | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| if n == 1 { | |||
| redis_client.Expire(redis_key.RewardSerialCounter(now), 5*time.Minute) | |||
| } | |||
| return now.Format("200601021504") + fmt.Sprint(rand.Intn(10)) + fmt.Sprintf("%02d", n), nil | |||
| } | |||
| @@ -9,17 +9,33 @@ import ( | |||
| "fmt" | |||
| ) | |||
| func Accomplish(userId int64, taskType string) { | |||
| go accomplish(userId, taskType) | |||
| func Accomplish(action models.Action) { | |||
| switch action.OpType { | |||
| case models.ActionCreateRepo, | |||
| models.ActionCreateImage: | |||
| if action.Repo.IsPrivate { | |||
| return | |||
| } | |||
| case models.ActionCreateDebugGPUTask, | |||
| models.ActionCreateDebugNPUTask, | |||
| models.ActionCreateTrainTask, | |||
| models.ActionCreateInferenceTask, | |||
| models.ActionCreateBenchMarkTask, | |||
| models.ActionCreateGPUTrainTask: | |||
| action.OpType = models.ActionCreateCloudbrainTask | |||
| } | |||
| go accomplish(action) | |||
| } | |||
| func accomplish(userId int64, taskType string) error { | |||
| func accomplish(action models.Action) error { | |||
| defer func() { | |||
| if err := recover(); err != nil { | |||
| combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) | |||
| log.Error("PANIC:%v", combinedErr) | |||
| } | |||
| }() | |||
| userId := action.ActUserID | |||
| taskType := fmt.Sprint(action.OpType) | |||
| //get task config | |||
| config, err := GetTaskConfig(taskType) | |||
| @@ -33,7 +49,7 @@ func accomplish(userId int64, taskType string) error { | |||
| } | |||
| //is limited? | |||
| if isLimited(userId, config) { | |||
| if isLimited(userId, config, limiter.JustReject) { | |||
| log.Info("task accomplish maximum times are reached,userId=%d taskType=%s", userId, taskType) | |||
| return nil | |||
| } | |||
| @@ -45,6 +61,7 @@ func accomplish(userId int64, taskType string) error { | |||
| ConfigId: config.ID, | |||
| TaskCode: config.TaskCode, | |||
| UserId: userId, | |||
| ActionId: action.ID, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| @@ -54,6 +71,7 @@ func accomplish(userId int64, taskType string) error { | |||
| reward.Operate(&models.RewardOperateContext{ | |||
| SourceType: models.SourceTypeAccomplishTask, | |||
| SourceId: logId, | |||
| Tittle: config.Tittle, | |||
| Reward: models.Reward{ | |||
| Amount: config.AwardAmount, | |||
| Type: models.GetRewardTypeInstance(config.AwardType), | |||
| @@ -61,13 +79,14 @@ func accomplish(userId int64, taskType string) error { | |||
| TargetUserId: userId, | |||
| RequestId: logId, | |||
| OperateType: models.OperateTypeIncrease, | |||
| RejectPolicy: limiter.FillUp, | |||
| }) | |||
| return nil | |||
| } | |||
| func isLimited(userId int64, config *models.TaskConfig) bool { | |||
| if err := limiter.CheckLimit(config.TaskCode, models.LimitTypeTask, userId, 1); err != nil { | |||
| func isLimited(userId int64, config *models.TaskConfig, rejectPolicy limiter.LimiterRejectPolicy) bool { | |||
| if _, err := limiter.CheckLimit(config.TaskCode, models.LimitTypeTask, userId, 1, rejectPolicy); err != nil { | |||
| return true | |||
| } | |||
| return false | |||