Browse Source

#2225

update
pull/2885/head
chenyifan01 3 years ago
parent
commit
7a3cc57f9f
38 changed files with 591 additions and 298 deletions
  1. +10
    -0
      models/action.go
  2. +3
    -3
      models/attachment.go
  3. +12
    -0
      models/error.go
  4. +8
    -0
      models/limit_config.go
  5. +1
    -0
      models/models.go
  6. +4
    -1
      models/repo_watch.go
  7. +46
    -0
      models/reward_admin_log.go
  8. +80
    -4
      models/reward_operate_record.go
  9. +6
    -5
      models/reward_periodic_task.go
  10. +6
    -5
      models/task_accomplish_log.go
  11. +0
    -30
      models/task_config.go
  12. +6
    -1
      modules/auth/wechat/event_handle.go
  13. +4
    -4
      modules/cloudbrain/resty.go
  14. +1
    -1
      modules/cron/tasks_basic.go
  15. +103
    -0
      modules/notification/action/action.go
  16. +4
    -3
      modules/notification/base/notifier.go
  17. +5
    -3
      modules/notification/base/null.go
  18. +7
    -8
      modules/notification/notification.go
  19. +0
    -157
      modules/notification/task/task.go
  20. +2
    -2
      modules/redis/redis_client/client.go
  21. +4
    -1
      modules/redis/redis_key/reward_redis_key.go
  22. +10
    -0
      modules/redis/redis_key/serial_redis_key.go
  23. +7
    -3
      modules/setting/setting.go
  24. +6
    -6
      routers/repo/cloudbrain.go
  25. +4
    -4
      routers/repo/modelarts.go
  26. +46
    -0
      routers/reward/point/point.go
  27. +4
    -0
      routers/routes/routes.go
  28. +15
    -0
      routers/task/task.go
  29. +1
    -1
      routers/user/setting/profile.go
  30. +50
    -0
      services/reward/admin_operate.go
  31. +10
    -7
      services/reward/cloubrain_deduct.go
  32. +11
    -28
      services/reward/limiter/limiter.go
  33. +44
    -10
      services/reward/operator.go
  34. +4
    -4
      services/reward/period_task.go
  35. +1
    -1
      services/reward/point/point_operate.go
  36. +20
    -0
      services/reward/record.go
  37. +21
    -0
      services/reward/serial.go
  38. +25
    -6
      services/task/task.go

+ 10
- 0
models/action.go View File

@@ -58,6 +58,16 @@ const (
ActionCreateBenchMarkTask //29 ActionCreateBenchMarkTask //29
ActionCreateNewModelTask //30 ActionCreateNewModelTask //30
ActionCreateGPUTrainTask //31 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 // Action represents user operation type and other information to


+ 3
- 3
models/attachment.go View File

@@ -654,9 +654,9 @@ func Attachments(opts *AttachmentsOptions) ([]*AttachmentInfo, int64, error) {
return attachments, count, nil 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 nil, err
} }
return r, nil return r, nil


+ 12
- 0
models/error.go View File

@@ -2024,3 +2024,15 @@ func IsErrRecordNotExist(err error) bool {
func (err ErrRecordNotExist) Error() string { func (err ErrRecordNotExist) Error() string {
return fmt.Sprintf("record not exist in database") 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")
}

+ 8
- 0
models/limit_config.go View File

@@ -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 { type LimitConfig struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
Tittle string Tittle string


+ 1
- 0
models/models.go View File

@@ -151,6 +151,7 @@ func init() {
new(RewardPeriodicTask), new(RewardPeriodicTask),
new(PointAccountLog), new(PointAccountLog),
new(PointAccount), new(PointAccount),
new(RewardAdminLog),
) )


tablesStatistic = append(tablesStatistic, tablesStatistic = append(tablesStatistic,


+ 4
- 1
models/repo_watch.go View File

@@ -25,6 +25,7 @@ const (
) )


var ActionChan = make(chan *Action, 200) var ActionChan = make(chan *Action, 200)
var ActionChan4Task = make(chan Action, 200)


// Watch is connection request for receiving repository notification. // Watch is connection request for receiving repository notification.
type Watch struct { type Watch struct {
@@ -199,6 +200,9 @@ func notifyWatchers(e Engine, actions ...*Action) error {
if _, err = e.InsertOne(act); err != nil { if _, err = e.InsertOne(act); err != nil {
return fmt.Errorf("insert new actioner: %v", err) 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 { if repoChanged {
act.loadRepo() act.loadRepo()
@@ -279,7 +283,6 @@ func notifyWatchers(e Engine, actions ...*Action) error {


// NotifyWatchers creates batch of actions for every watcher. // NotifyWatchers creates batch of actions for every watcher.
func NotifyWatchers(actions ...*Action) error { func NotifyWatchers(actions ...*Action) error {

error := notifyWatchers(x, actions...) error := notifyWatchers(x, actions...)
producer(actions...) producer(actions...)
return error return error


+ 46
- 0
models/reward_admin_log.go View File

@@ -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
}

+ 80
- 4
models/reward_operate_record.go View File

@@ -95,6 +95,7 @@ func GetRewardOperateTypeInstance(s string) RewardOperateType {
const ( const (
OperateTypeIncrease RewardOperateType = "INCREASE" OperateTypeIncrease RewardOperateType = "INCREASE"
OperateTypeDecrease RewardOperateType = "DECREASE" OperateTypeDecrease RewardOperateType = "DECREASE"
OperateTypeNull RewardOperateType = "NIL"
) )


const ( const (
@@ -105,11 +106,18 @@ const (


const Semicolon = ";" const Semicolon = ";"


type RewardOperateOrderBy string

const (
RewardOrderByID RewardOperateOrderBy = "id"
)

type RewardOperateRecord struct { type RewardOperateRecord struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
RecordId string `xorm:"INDEX NOT NULL"`
SerialNo string `xorm:"INDEX NOT NULL"`
UserId int64 `xorm:"INDEX NOT NULL"` UserId int64 `xorm:"INDEX NOT NULL"`
Amount int64 `xorm:"NOT NULL"` Amount int64 `xorm:"NOT NULL"`
Tittle string
RewardType string `xorm:"NOT NULL"` RewardType string `xorm:"NOT NULL"`
SourceType string `xorm:"NOT NULL"` SourceType string `xorm:"NOT NULL"`
SourceId string `xorm:"INDEX NOT NULL"` SourceId string `xorm:"INDEX NOT NULL"`
@@ -121,6 +129,32 @@ type RewardOperateRecord struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` 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) { func getPointOperateRecord(tl *RewardOperateRecord) (*RewardOperateRecord, error) {
has, err := x.Get(tl) has, err := x.Get(tl)
if err != nil { if err != nil {
@@ -140,14 +174,14 @@ func GetPointOperateRecordBySourceTypeAndRequestId(sourceType, requestId, operat
return getPointOperateRecord(t) return getPointOperateRecord(t)
} }


func GetPointOperateRecordByRecordId(recordId string) (*RewardOperateRecord, error) {
func GetPointOperateRecordBySerialNo(serialNo string) (*RewardOperateRecord, error) {
t := &RewardOperateRecord{ t := &RewardOperateRecord{
RecordId: recordId,
SerialNo: serialNo,
} }
return getPointOperateRecord(t) return getPointOperateRecord(t)
} }


func InsertAwardOperateRecord(tl *RewardOperateRecord) (int64, error) {
func InsertRewardOperateRecord(tl *RewardOperateRecord) (int64, error) {
return x.Insert(tl) return x.Insert(tl)
} }


@@ -175,11 +209,13 @@ func SumRewardAmountInTaskPeriod(rewardType string, sourceType string, userId in
type RewardOperateContext struct { type RewardOperateContext struct {
SourceType SourceType SourceType SourceType
SourceId string SourceId string
Tittle string
Remark string Remark string
Reward Reward Reward Reward
TargetUserId int64 TargetUserId int64
RequestId string RequestId string
OperateType RewardOperateType OperateType RewardOperateType
RejectPolicy LimiterRejectPolicy
} }


type Reward struct { type Reward struct {
@@ -202,3 +238,43 @@ type UserRewardOperation struct {
func AppendRemark(remark, appendStr string) string { func AppendRemark(remark, appendStr string) string {
return strings.TrimPrefix(remark+Semicolon+appendStr, Semicolon) 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
}

+ 6
- 5
models/reward_periodic_task.go View File

@@ -29,7 +29,7 @@ func (r PeriodType) Name() string {


type RewardPeriodicTask struct { type RewardPeriodicTask struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
OperateRecordId string `xorm:"INDEX NOT NULL"`
OperateSerialNo string `xorm:"INDEX NOT NULL"`
DelaySeconds int64 DelaySeconds int64
IntervalSeconds int64 IntervalSeconds int64
Amount int64 `xorm:"NOT NULL"` Amount int64 `xorm:"NOT NULL"`
@@ -45,6 +45,7 @@ type StartPeriodicTaskOpts struct {
SourceType SourceType SourceType SourceType
SourceId string SourceId string
Remark string Remark string
Tittle string
TargetUserId int64 TargetUserId int64
RequestId string RequestId string
OperateType RewardOperateType OperateType RewardOperateType
@@ -76,7 +77,7 @@ func IncrRewardTaskSuccessCount(t RewardPeriodicTask, count int64, nextTime time
sess.Rollback() sess.Rollback()
return err 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 { if err != nil {
sess.Rollback() sess.Rollback()
return err return err
@@ -88,7 +89,7 @@ func IncrRewardTaskSuccessCount(t RewardPeriodicTask, count int64, nextTime time
func GetPeriodicTaskBySourceIdAndType(sourceType SourceType, sourceId string, operateType RewardOperateType) (*RewardPeriodicTask, error) { func GetPeriodicTaskBySourceIdAndType(sourceType SourceType, sourceId string, operateType RewardOperateType) (*RewardPeriodicTask, error) {
r := RewardPeriodicTask{} r := RewardPeriodicTask{}
_, err := x.SQL("select rpt.* from reward_periodic_task rpt "+ _, 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) " where ror.source_type = ? and source_id = ? and operate_type = ? ", sourceType.Name(), sourceId, operateType.Name()).Get(&r)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -96,7 +97,7 @@ func GetPeriodicTaskBySourceIdAndType(sourceType SourceType, sourceId string, op
return &r, nil 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() sess := x.NewSession()
defer sess.Close() defer sess.Close()
_, err := sess.Where("id = ? and status = ?", taskId, PeriodicTaskStatusRunning).Update(&RewardPeriodicTask{Status: PeriodicTaskStatusFinished, FinishedUnix: timeutil.TimeStamp(stopTime.Unix())}) _, 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() sess.Rollback()
return err 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 { if err != nil {
sess.Rollback() sess.Rollback()
return err return err


+ 6
- 5
models/task_accomplish_log.go View File

@@ -6,11 +6,12 @@ import (
) )


type TaskAccomplishLog struct { 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"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
} }




+ 0
- 30
models/task_config.go View File

@@ -5,36 +5,6 @@ import (
) )


const ( 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" PeriodNotCycle = "NOT_CYCLE"
PeriodDaily = "DAILY" PeriodDaily = "DAILY"
) )


+ 6
- 1
modules/auth/wechat/event_handle.go View File

@@ -1,6 +1,7 @@
package wechat package wechat


import ( import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"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"
@@ -72,6 +73,10 @@ func HandleSubscribeEvent(we WechatEvent) string {
jsonStr, _ := json.Marshal(qrCache) jsonStr, _ := json.Marshal(qrCache)
redis_client.Setex(redis_key.WechatBindingUserIdKey(sceneStr), string(jsonStr), 60*time.Second) 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 return BIND_REPLY_SUCCESS
} }

+ 4
- 4
modules/cloudbrain/resty.go View File

@@ -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) 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) imageTag := strings.TrimSpace(params.ImageTag)


dbImage, err := models.GetImageByTag(imageTag) dbImage, err := models.GetImageByTag(imageTag)
@@ -314,12 +314,12 @@ sendjob:
}) })
if err == nil { if err == nil {
go updateImageStatus(image, isSetCreatedUnix, createTime) go updateImageStatus(image, isSetCreatedUnix, createTime)
notification.NotifyCreateImage(params.UID, image)
notification.NotifyCreateImage(doer, image)
} }
return err return err
} }


func CommitAdminImage(params models.CommitImageParams) error {
func CommitAdminImage(params models.CommitImageParams, doer *models.User) error {
imageTag := strings.TrimSpace(params.ImageTag) imageTag := strings.TrimSpace(params.ImageTag)
exist, err := models.IsImageExist(imageTag) exist, err := models.IsImageExist(imageTag)


@@ -357,7 +357,7 @@ func CommitAdminImage(params models.CommitImageParams) error {
return nil return nil
}) })
if err == nil { if err == nil {
notification.NotifyCreateImage(params.UID, image)
notification.NotifyCreateImage(doer, image)
} }
return err return err
} }


+ 1
- 1
modules/cron/tasks_basic.go View File

@@ -212,7 +212,7 @@ func registerRewardPeriodTask() {
RegisterTaskFatal("reward_period_task", &BaseConfig{ RegisterTaskFatal("reward_period_task", &BaseConfig{
Enabled: true, Enabled: true,
RunAtStart: true, RunAtStart: true,
Schedule: "@every 5m",
Schedule: "@every 1m",
}, func(ctx context.Context, _ *models.User, _ Config) error { }, func(ctx context.Context, _ *models.User, _ Config) error {
reward.StartRewardTask() reward.StartRewardTask()
return nil return nil


+ 103
- 0
modules/notification/action/action.go View File

@@ -5,6 +5,7 @@
package action package action


import ( import (
"code.gitea.io/gitea/modules/auth"
"encoding/json" "encoding/json"
"fmt" "fmt"
"path" "path"
@@ -345,3 +346,105 @@ func (a *actionNotifier) NotifyOtherTask(doer *models.User, repo *models.Reposit
log.Error("notifyWatchers: %v", err) 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)
}
}

+ 4
- 3
modules/notification/base/notifier.go View File

@@ -6,6 +6,7 @@ package base


import ( import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/repository"
) )


@@ -56,9 +57,9 @@ type Notifier interface {
NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string)


NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType) 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) 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) NotifyImageRecommend(optUser *models.User, imageId int64, action string)
NotifyChangeUserAvatar(user *models.User)
NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm)
} }

+ 5
- 3
modules/notification/base/null.go View File

@@ -6,6 +6,7 @@ package base


import ( import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/repository" "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) 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) NotifyImageRecommend(optUser *models.User, imageId int64, action string) {
} }


func (*NullNotifier) NotifyChangeUserAvatar(user *models.User) {
func (*NullNotifier) NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) {

} }

+ 7
- 8
modules/notification/notification.go View File

@@ -6,11 +6,11 @@ package notification


import ( import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/notification/action" "code.gitea.io/gitea/modules/notification/action"
"code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/notification/indexer" "code.gitea.io/gitea/modules/notification/indexer"
"code.gitea.io/gitea/modules/notification/mail" "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/ui"
"code.gitea.io/gitea/modules/notification/webhook" "code.gitea.io/gitea/modules/notification/webhook"
"code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/repository"
@@ -36,7 +36,6 @@ func NewContext() {
RegisterNotifier(indexer.NewNotifier()) RegisterNotifier(indexer.NewNotifier())
RegisterNotifier(webhook.NewNotifier()) RegisterNotifier(webhook.NewNotifier())
RegisterNotifier(action.NewNotifier()) RegisterNotifier(action.NewNotifier())
RegisterNotifier(task.NewNotifier())
} }


// NotifyUploadAttachment notifies attachment upload message to notifiers // NotifyUploadAttachment notifies attachment upload message to notifiers
@@ -273,9 +272,9 @@ func NotifySyncDeleteRef(pusher *models.User, repo *models.Repository, refType,
} }


// NotifyWechatBind notifies wechat bind // NotifyWechatBind notifies wechat bind
func NotifyWechatBind(userId int64, wechatOpenId string) {
func NotifyWechatBind(user *models.User, wechatOpenId string) {
for _, notifier := range notifiers { 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 // NotifyDatasetRecommend
func NotifyCreateImage(optUserId int64, image models.Image) {
func NotifyCreateImage(doer *models.User, image models.Image) {
for _, notifier := range notifiers { 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 // NotifyDatasetRecommend
func NotifyChangeUserAvatar(user *models.User) {
func NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) {
for _, notifier := range notifiers { for _, notifier := range notifiers {
notifier.NotifyChangeUserAvatar(user)
notifier.NotifyChangeUserAvatar(user, form)
} }
} }

+ 0
- 157
modules/notification/task/task.go View File

@@ -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)
}

+ 2
- 2
modules/redis/redis_client/client.go View File

@@ -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() redisClient := labelmsg.Get()
defer redisClient.Close() defer redisClient.Close()


_, err := redisClient.Do("EXPIRE", key, expireSeconds)
_, err := redisClient.Do("EXPIRE", key, int64(expireTime.Seconds()))
if err != nil { if err != nil {
return err return err
} }


+ 4
- 1
modules/redis/redis_key/reward_redis_key.go View File

@@ -1,6 +1,8 @@
package redis_key package redis_key


import "fmt"
import (
"fmt"
)


const REWARD_REDIS_PREFIX = "reward" const REWARD_REDIS_PREFIX = "reward"


@@ -11,6 +13,7 @@ func RewardOperateLock(requestId string, sourceType string, operateType string)
func RewardOperateNotification() string { func RewardOperateNotification() string {
return KeyJoin(REWARD_REDIS_PREFIX, "operate", "notification") return KeyJoin(REWARD_REDIS_PREFIX, "operate", "notification")
} }

func RewardTaskRunningLock(taskId int64) string { func RewardTaskRunningLock(taskId int64) string {
return KeyJoin(REWARD_REDIS_PREFIX, "periodic_task", fmt.Sprint(taskId), "lock") return KeyJoin(REWARD_REDIS_PREFIX, "periodic_task", fmt.Sprint(taskId), "lock")
} }

+ 10
- 0
modules/redis/redis_key/serial_redis_key.go View File

@@ -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")
}

+ 7
- 3
modules/setting/setting.go View File

@@ -232,7 +232,7 @@ var (
TimeoutStep: 10 * time.Second, TimeoutStep: 10 * time.Second,
MaxTimeout: 60 * time.Second, MaxTimeout: 60 * time.Second,
EventSourceUpdateTime: 10 * time.Second, EventSourceUpdateTime: 10 * time.Second,
RewardNotifyUpdateTime: 3 * time.Second,
RewardNotifyUpdateTime: 2 * time.Second,
}, },
Admin: struct { Admin: struct {
UserPagingNum int UserPagingNum int
@@ -549,7 +549,9 @@ var (
WechatAuthSwitch bool WechatAuthSwitch bool


//point config //point config
CloudBrainTaskPointPaySwitch bool
CloudBrainPaySwitch bool
CloudBrainPayDelay time.Duration
CloudBrainPayInterval time.Duration


//nginx proxy //nginx proxy
PROXYURL string PROXYURL string
@@ -1380,7 +1382,9 @@ func NewContext() {
WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(false) WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(false)


sec = Cfg.Section("point") 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() SetRadarMapConfig()




+ 6
- 6
routers/repo/cloudbrain.go View File

@@ -233,7 +233,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
if !reward.IsPointBalanceEnough(ctx.User.ID, jobType, resourceSpecId) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, jobType, resourceSpecId)
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("point balance not enough", tpl, &form)
ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tpl, &form)
return return
} }


@@ -319,7 +319,7 @@ func CloudBrainRestart(ctx *context.Context) {
if !reward.IsPointBalanceEnough(ctx.User.ID, task.JobType, task.ResourceSpecId) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, task.JobType, task.ResourceSpecId)
resultCode = "-1" resultCode = "-1"
errorMsg = "insufficient points balance"
errorMsg = models.ErrInsufficientPointsBalance{}.Error()
break break
} }


@@ -737,7 +737,7 @@ func CloudBrainAdminCommitImage(ctx *context.Context, form auth.CommitAdminImage
UID: ctx.User.ID, UID: ctx.User.ID,
Type: models.GetRecommondType(form.IsRecommend), Type: models.GetRecommondType(form.IsRecommend),
Place: form.Place, Place: form.Place,
})
}, ctx.User)
if err != nil { if err != nil {
log.Error("CommitImagefailed") log.Error("CommitImagefailed")
if models.IsErrImageTagExist(err) { if models.IsErrImageTagExist(err) {
@@ -784,7 +784,7 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain
CloudBrainType: form.Type, CloudBrainType: form.Type,
Topics: validTopics, Topics: validTopics,
UID: ctx.User.ID, UID: ctx.User.ID,
})
}, ctx.User)
if err != nil { if err != nil {
log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"]) log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"])
if models.IsErrImageTagExist(err) { 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) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId)
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("point balance not enough", tplCloudBrainBenchmarkNew, &form)
ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplCloudBrainBenchmarkNew, &form)
return return
} }


@@ -2024,7 +2024,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
if !reward.IsPointBalanceEnough(ctx.User.ID, jobType, resourceSpecId) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, jobType, resourceSpecId)
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("point balance not enough", tpl, &form)
ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tpl, &form)
return return
} }




+ 4
- 4
routers/repo/modelarts.go View File

@@ -210,7 +210,7 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
if !reward.IsPointBalanceEnough(ctx.User.ID, string(models.JobTypeDebug), resourceSpecId) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId)
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("point balance not enough", tplModelArtsNotebookNew, &form)
ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplModelArtsNotebookNew, &form)
return return
} }
count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID) 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) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, task.JobType, task.ResourceSpecId)
resultCode = "-1" resultCode = "-1"
errorMsg = "point balance not enough"
errorMsg = models.ErrInsufficientPointsBalance{}.Error()
break break
return return
} }
@@ -1005,7 +1005,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
if !reward.IsPointBalanceEnough(ctx.User.ID, string(models.JobTypeTrain), resourceSpecId) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId)
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("point balance not enough", tplModelArtsTrainJobNew, &form)
ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplModelArtsTrainJobNew, &form)
return return
} }
count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) 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) { 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) log.Error("point balance is not enough,userId=%d jobType=%s resourceSpecId=%d", ctx.User.ID, string(models.JobTypeBenchmark), resourceSpecId)
inferenceJobErrorNewDataPrepare(ctx, form) inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr("point balance not enough", tplModelArtsInferenceJobNew, &form)
ctx.RenderWithErr(models.ErrInsufficientPointsBalance{}.Error(), tplModelArtsInferenceJobNew, &form)
return return
} }
count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID)


+ 46
- 0
routers/reward/point/point.go View File

@@ -1,8 +1,10 @@
package point package point


import ( import (
"code.gitea.io/gitea/models"
"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/point/account" "code.gitea.io/gitea/services/reward/point/account"
"net/http" "net/http"
) )
@@ -29,3 +31,47 @@ func GetPointAccount(ctx *context.Context) {
} }
ctx.JSON(http.StatusOK, response.SuccessWithData(res)) 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())
}

+ 4
- 0
routers/routes/routes.go View File

@@ -324,6 +324,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/", routers.Home) m.Get("/", routers.Home)
m.Get("/dashboard", routers.Dashboard) m.Get("/dashboard", routers.Dashboard)
go routers.SocketManager.Run() go routers.SocketManager.Run()
go task.RunTask()
m.Get("/action/notification", routers.ActionNotification) m.Get("/action/notification", routers.ActionNotification)
m.Get("/reward/notification", routers.ActionNotification) m.Get("/reward/notification", routers.ActionNotification)
m.Get("/recommend/org", routers.RecommendOrgFromPromote) m.Get("/recommend/org", routers.RecommendOrgFromPromote)
@@ -594,6 +595,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/reward/point", func() { m.Group("/reward/point", func() {
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("/operate", binding.Bind(models.AdminRewardOperateReq{}), point.OperatePointAccountBalance)
}) })


m.Group("/task/config", func() { 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", bindIgnErr(models.TaskConfigWithLimit{}), task.AddTaskConfig)
m.Post("/add/batch", bindIgnErr(models.BatchLimitConfigVO{}), task.BatchAddTaskConfig) m.Post("/add/batch", bindIgnErr(models.BatchLimitConfigVO{}), task.BatchAddTaskConfig)
}) })

}, adminReq) }, adminReq)
// ***** END: Admin ***** // ***** END: Admin *****


@@ -1330,6 +1333,7 @@ func RegisterRoutes(m *macaron.Macaron) {


m.Group("/reward/point", func() { m.Group("/reward/point", func() {
m.Get("/account", point.GetPointAccount) m.Get("/account", point.GetPointAccount)
m.Get("/record/list", point.GetPointRecordList)
}, reqSignIn) }, reqSignIn)


if setting.API.EnableSwagger { if setting.API.EnableSwagger {


+ 15
- 0
routers/task/task.go View File

@@ -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)
}
}
}

+ 1
- 1
routers/user/setting/profile.go View File

@@ -166,7 +166,7 @@ func AvatarPost(ctx *context.Context, form auth.AvatarForm) {
if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil { if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil {
ctx.Flash.Error(err.Error()) ctx.Flash.Error(err.Error())
} else { } else {
notification.NotifyChangeUserAvatar(ctx.User)
notification.NotifyChangeUserAvatar(ctx.User, form)
ctx.Flash.Success(ctx.Tr("settings.update_avatar_success")) ctx.Flash.Success(ctx.Tr("settings.update_avatar_success"))
} }




+ 50
- 0
services/reward/admin_operate.go View File

@@ -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
}

+ 10
- 7
services/reward/cloubrain_deduct.go View File

@@ -15,9 +15,11 @@ var (
TrainResourceSpecs *models.ResourceSpecs TrainResourceSpecs *models.ResourceSpecs
) )


const RUN_CLOUDBRAIN_TASK_TITTLE = "运行云脑任务"

//IsPointBalanceEnough check whether the user's point balance is bigger than task unit price //IsPointBalanceEnough check whether the user's point balance is bigger than task unit price
func IsPointBalanceEnough(targetUserId int64, jobType string, resourceSpecId int) bool { func IsPointBalanceEnough(targetUserId int64, jobType string, resourceSpecId int) bool {
if !setting.CloudBrainTaskPointPaySwitch {
if !setting.CloudBrainPaySwitch {
return true return true
} }
spec := getResourceSpec(jobType, resourceSpecId) spec := getResourceSpec(jobType, resourceSpecId)
@@ -33,7 +35,7 @@ func IsPointBalanceEnough(targetUserId int64, jobType string, resourceSpecId int
} }


func StartCloudBrainPointDeductTask(task models.Cloudbrain) { func StartCloudBrainPointDeductTask(task models.Cloudbrain) {
if !setting.CloudBrainTaskPointPaySwitch {
if !setting.CloudBrainPaySwitch {
return return
} }


@@ -48,11 +50,12 @@ func StartCloudBrainPointDeductTask(task models.Cloudbrain) {
TargetUserId: task.UserID, TargetUserId: task.UserID,
RequestId: getCloudBrainPointTaskSourceId(task), RequestId: getCloudBrainPointTaskSourceId(task),
OperateType: models.OperateTypeDecrease, OperateType: models.OperateTypeDecrease,
Delay: 30 * time.Minute,
Interval: 60 * time.Minute,
Delay: setting.CloudBrainPayDelay,
Interval: setting.CloudBrainPayInterval,
UnitAmount: spec.UnitPrice, UnitAmount: spec.UnitPrice,
RewardType: models.RewardTypePoint, RewardType: models.RewardTypePoint,
StartTime: time.Unix(int64(task.StartTime), 0), 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 { 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 { func getResourceSpec(jobType string, resourceSpecId int) *models.ResourceSpec {
@@ -100,11 +103,11 @@ func StartCloudbrainPointDeductTask() {
}() }()
log.Debug("try to run CloudbrainPointDeductTask") log.Debug("try to run CloudbrainPointDeductTask")
end := time.Now() end := time.Now()
start := end.Add(5 * time.Minute)
start := end.Add(-5 * time.Minute)
if firstTimeFlag { if firstTimeFlag {
//When it is executed for the first time, it needs to process the tasks of the last 1 hours. //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 //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 firstTimeFlag = false
} }




+ 11
- 28
services/reward/limiter/limiter.go View File

@@ -12,14 +12,6 @@ import (
"time" "time"
) )


type limiterRejectPolicy string

const (
JustReject limiterRejectPolicy = "JUST_REJECT"
PermittedOnce limiterRejectPolicy = "PERMITTED_ONCE"
FillUp limiterRejectPolicy = "FillUp"
)

type limiterRunner struct { type limiterRunner struct {
limiters []models.LimitConfig limiters []models.LimitConfig
index int index int
@@ -27,7 +19,7 @@ type limiterRunner struct {
amount int64 amount int64
limitCode string limitCode string
limitType models.LimitType limitType models.LimitType
rejectPolicy limiterRejectPolicy
rejectPolicy models.LimiterRejectPolicy
resultMap map[int]limitResult resultMap map[int]limitResult
minRealAmount int64 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{ return &limiterRunner{
userId: userId, userId: userId,
amount: amount, amount: amount,
@@ -149,7 +141,7 @@ func (l *limiterRunner) limit(r models.LimitConfig) error {
usedNum, err = redis_client.IncrBy(redisKey, n) usedNum, err = redis_client.IncrBy(redisKey, n)
} }
if p != nil { if p != nil {
redis_client.Expire(redisKey, int64(p.LeftTime.Seconds()))
redis_client.Expire(redisKey, p.LeftTime)
} }
} }
if usedNum > r.LimitNum { 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)) return errors.New(fmt.Sprintf("%s:over limit", r.Tittle))
} }
switch l.rejectPolicy { switch l.rejectPolicy {
case FillUp:
case models.FillUp:
exceed := usedNum - r.LimitNum exceed := usedNum - r.LimitNum
realAmount := l.amount - exceed realAmount := l.amount - exceed
redis_client.IncrBy(redisKey, -1*exceed) redis_client.IncrBy(redisKey, -1*exceed)
l.resultMap[l.index] = newLimitResult(true, l.amount, realAmount) l.resultMap[l.index] = newLimitResult(true, l.amount, realAmount)
return nil return nil
case JustReject:
case models.JustReject:
redis_client.IncrBy(redisKey, -1*l.amount) redis_client.IncrBy(redisKey, -1*l.amount)
return errors.New(fmt.Sprintf("%s:over limit", r.Tittle)) 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) l.resultMap[l.index] = newLimitResult(false, l.amount, l.amount)
return nil 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() err := r.Run()
if err != nil { if err != nil {
return 0, err return 0, err
@@ -209,18 +204,6 @@ func CheckLimitWithFillUp(limitCode string, limitType models.LimitType, userId,
return r.minRealAmount, nil 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) { func GetLimiters(limitCode string, limitType models.LimitType) ([]models.LimitConfig, error) {
limiters, err := GetLimitersByLimitType(limitType) limiters, err := GetLimitersByLimitType(limitType)
if err != nil { if err != nil {


+ 44
- 10
services/reward/operator.go View File

@@ -5,7 +5,6 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"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"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/reward/point" "code.gitea.io/gitea/services/reward/point"
"errors" "errors"
"fmt" "fmt"
@@ -69,7 +68,7 @@ func Operate(ctx *models.RewardOperateContext) error {
} }


//new reward operate record //new reward operate record
recordId, err := initAwardOperateRecord(ctx)
recordId, err := initRewardOperateRecord(ctx)
if err != nil { if err != nil {
return err 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{ record := &models.RewardOperateRecord{
RecordId: util.UUID(),
UserId: ctx.TargetUserId, UserId: ctx.TargetUserId,
Amount: ctx.Reward.Amount, Amount: ctx.Reward.Amount,
RewardType: ctx.Reward.Type.Name(), RewardType: ctx.Reward.Type.Name(),
@@ -122,17 +124,22 @@ func initAwardOperateRecord(ctx *models.RewardOperateContext) (string, error) {
OperateType: ctx.OperateType.Name(), OperateType: ctx.OperateType.Name(),
Status: models.OperateStatusOperating, Status: models.OperateStatusOperating,
Remark: ctx.Remark, Remark: ctx.Remark,
Tittle: ctx.Tittle,
SerialNo: sn,
} }
_, err := models.InsertAwardOperateRecord(record)
_, err = models.InsertRewardOperateRecord(record)
if err != nil { if err != nil {
return "", err return "", err
} }
return record.RecordId, nil
return record.SerialNo, nil
} }


func createPeriodicRewardOperateRecord(ctx *models.StartPeriodicTaskOpts) (string, error) { func createPeriodicRewardOperateRecord(ctx *models.StartPeriodicTaskOpts) (string, error) {
sn, err := generateOperateSerialNo(ctx.OperateType, ctx.RewardType)
if err != nil {
return "", err
}
record := &models.RewardOperateRecord{ record := &models.RewardOperateRecord{
RecordId: util.UUID(),
UserId: ctx.TargetUserId, UserId: ctx.TargetUserId,
Amount: 0, Amount: 0,
RewardType: ctx.RewardType.Name(), RewardType: ctx.RewardType.Name(),
@@ -142,12 +149,14 @@ func createPeriodicRewardOperateRecord(ctx *models.StartPeriodicTaskOpts) (strin
OperateType: ctx.OperateType.Name(), OperateType: ctx.OperateType.Name(),
Status: models.OperateStatusOperating, Status: models.OperateStatusOperating,
Remark: ctx.Remark, Remark: ctx.Remark,
Tittle: ctx.Tittle,
SerialNo: sn,
} }
_, err := models.InsertAwardOperateRecord(record)
_, err = models.InsertRewardOperateRecord(record)
if err != nil { if err != nil {
return "", err return "", err
} }
return record.RecordId, nil
return record.SerialNo, nil
} }


func updateAwardOperateRecordStatus(sourceType, requestId, oldStatus, newStatus string) error { func updateAwardOperateRecordStatus(sourceType, requestId, oldStatus, newStatus string) error {
@@ -230,5 +239,30 @@ func StopPeriodicTask(sourceType models.SourceType, sourceId string, operateType
} }
now := time.Now() now := time.Now()
RunRewardTask(*task, 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
} }

+ 4
- 4
services/reward/period_task.go View File

@@ -15,7 +15,7 @@ func NewRewardPeriodicTask(operateRecordId string, opts *models.StartPeriodicTas
task.DelaySeconds = int64(opts.Delay.Seconds()) task.DelaySeconds = int64(opts.Delay.Seconds())
task.IntervalSeconds = int64(opts.Interval.Seconds()) task.IntervalSeconds = int64(opts.Interval.Seconds())
task.Amount = opts.UnitAmount task.Amount = opts.UnitAmount
task.OperateRecordId = operateRecordId
task.OperateSerialNo = operateRecordId
task.Status = models.PeriodicTaskStatusRunning task.Status = models.PeriodicTaskStatusRunning
task.NextExecuteTime = timeutil.TimeStamp(opts.StartTime.Add(opts.Delay).Unix()) task.NextExecuteTime = timeutil.TimeStamp(opts.StartTime.Add(opts.Delay).Unix())


@@ -54,9 +54,9 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) {
return return
} }
defer lock.UnLock() defer lock.UnLock()
record, err := models.GetPointOperateRecordByRecordId(t.OperateRecordId)
record, err := models.GetPointOperateRecordBySerialNo(t.OperateSerialNo)
if err != nil { if err != nil {
log.Error("RunRewardTask. GetPointOperateRecordByRecordId error. %v", err)
log.Error("RunRewardTask. GetPointOperateRecordBySerialNo error. %v", err)
return return
} }
if record.Status != models.OperateStatusOperating { if record.Status != models.OperateStatusOperating {
@@ -75,7 +75,7 @@ func RunRewardTask(t models.RewardPeriodicTask, now time.Time) {
} }
err = operator.Operate(&models.RewardOperateContext{ err = operator.Operate(&models.RewardOperateContext{
SourceType: models.SourceTypeRunCloudbrainTask, SourceType: models.SourceTypeRunCloudbrainTask,
SourceId: t.OperateRecordId,
SourceId: t.OperateSerialNo,
Reward: models.Reward{ Reward: models.Reward{
Amount: n * t.Amount, Amount: n * t.Amount,
Type: models.GetRewardTypeInstance(record.RewardType), Type: models.GetRewardTypeInstance(record.RewardType),


+ 1
- 1
services/reward/point/point_operate.go View File

@@ -18,7 +18,7 @@ type PointOperator struct {
} }


func (operator *PointOperator) IsLimited(ctx *models.RewardOperateContext) bool { 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 { if err != nil {
return true return true
} }


+ 20
- 0
services/reward/record.go View File

@@ -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
}

+ 21
- 0
services/reward/serial.go View File

@@ -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
}

+ 25
- 6
services/task/task.go View File

@@ -9,17 +9,33 @@ import (
"fmt" "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() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
log.Error("PANIC:%v", combinedErr) log.Error("PANIC:%v", combinedErr)
} }
}() }()
userId := action.ActUserID
taskType := fmt.Sprint(action.OpType)


//get task config //get task config
config, err := GetTaskConfig(taskType) config, err := GetTaskConfig(taskType)
@@ -33,7 +49,7 @@ func accomplish(userId int64, taskType string) error {
} }


//is limited? //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) log.Info("task accomplish maximum times are reached,userId=%d taskType=%s", userId, taskType)
return nil return nil
} }
@@ -45,6 +61,7 @@ func accomplish(userId int64, taskType string) error {
ConfigId: config.ID, ConfigId: config.ID,
TaskCode: config.TaskCode, TaskCode: config.TaskCode,
UserId: userId, UserId: userId,
ActionId: action.ID,
}) })
if err != nil { if err != nil {
return err return err
@@ -54,6 +71,7 @@ func accomplish(userId int64, taskType string) error {
reward.Operate(&models.RewardOperateContext{ reward.Operate(&models.RewardOperateContext{
SourceType: models.SourceTypeAccomplishTask, SourceType: models.SourceTypeAccomplishTask,
SourceId: logId, SourceId: logId,
Tittle: config.Tittle,
Reward: models.Reward{ Reward: models.Reward{
Amount: config.AwardAmount, Amount: config.AwardAmount,
Type: models.GetRewardTypeInstance(config.AwardType), Type: models.GetRewardTypeInstance(config.AwardType),
@@ -61,13 +79,14 @@ func accomplish(userId int64, taskType string) error {
TargetUserId: userId, TargetUserId: userId,
RequestId: logId, RequestId: logId,
OperateType: models.OperateTypeIncrease, OperateType: models.OperateTypeIncrease,
RejectPolicy: limiter.FillUp,
}) })


return nil 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 true
} }
return false return false


Loading…
Cancel
Save