| @@ -89,6 +89,7 @@ type Action struct { | |||
| IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| Content string `xorm:"TEXT"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| Cloudbrain *Cloudbrain `xorm:"-"` | |||
| } | |||
| type ActionShow struct { | |||
| @@ -100,6 +101,7 @@ type ActionShow struct { | |||
| IssueInfos []string | |||
| CommentLink string | |||
| IssueTitle string | |||
| Cloudbrain *CloudbrainShow4Action | |||
| } | |||
| // GetOpType gets the ActionType of this action. | |||
| @@ -256,22 +258,25 @@ func (a *Action) ToShow() *ActionShow { | |||
| actionShow.CommentLink = a.GetCommentLink() | |||
| } | |||
| if a.Cloudbrain != nil { | |||
| c := &CloudbrainShow4Action{ | |||
| ID: a.Cloudbrain.ID, | |||
| Type: a.Cloudbrain.Type, | |||
| JobType: a.Cloudbrain.JobType, | |||
| DisplayJobName: a.Cloudbrain.DisplayJobName, | |||
| ComputeResource: a.Cloudbrain.ComputeResource, | |||
| } | |||
| actionShow.Cloudbrain = c | |||
| } | |||
| return actionShow | |||
| } | |||
| func GetTaskOptType(action Action) ActionType { | |||
| switch action.OpType { | |||
| case ActionCreateDebugGPUTask, | |||
| ActionCreateDebugNPUTask, | |||
| ActionCreateTrainTask, | |||
| ActionCreateInferenceTask, | |||
| ActionCreateBenchMarkTask, | |||
| ActionCreateGPUTrainTask: | |||
| if action.IsCloudbrainAction() { | |||
| return ActionCreateCloudbrainTask | |||
| default: | |||
| return action.OpType | |||
| } | |||
| return action.OpType | |||
| } | |||
| // GetRepositoryFromMatch returns a *Repository from a username and repo strings | |||
| @@ -371,6 +376,19 @@ func (a *Action) GetIssueContent() string { | |||
| return issue.Content | |||
| } | |||
| func (a *Action) IsCloudbrainAction() bool { | |||
| switch a.OpType { | |||
| case ActionCreateDebugGPUTask, | |||
| ActionCreateDebugNPUTask, | |||
| ActionCreateTrainTask, | |||
| ActionCreateInferenceTask, | |||
| ActionCreateBenchMarkTask, | |||
| ActionCreateGPUTrainTask: | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| // GetFeedsOptions options for retrieving feeds | |||
| type GetFeedsOptions struct { | |||
| RequestedUser *User // the user we want activity for | |||
| @@ -4,7 +4,10 @@ | |||
| package models | |||
| import "fmt" | |||
| import ( | |||
| "fmt" | |||
| "strconv" | |||
| ) | |||
| // ActionList defines a list of actions | |||
| type ActionList []*Action | |||
| @@ -111,7 +114,9 @@ func (actions ActionList) loadComments(e Engine) ([]*Comment, error) { | |||
| } | |||
| for _, action := range actions { | |||
| action.Comment = commentMaps[action.CommentID] | |||
| if action.CommentID > 0 { | |||
| action.Comment = commentMaps[action.CommentID] | |||
| } | |||
| } | |||
| return valuesComment(commentMaps), nil | |||
| } | |||
| @@ -121,6 +126,52 @@ func (actions ActionList) LoadComments() ([]*Comment, error) { | |||
| return actions.loadComments(x) | |||
| } | |||
| func (actions ActionList) getCloudbrainIDs() []int64 { | |||
| cloudbrainIDs := make(map[int64]struct{}, 0) | |||
| for _, action := range actions { | |||
| if !action.IsCloudbrainAction() { | |||
| continue | |||
| } | |||
| cloudbrainId, _ := strconv.ParseInt(action.Content, 10, 64) | |||
| if _, ok := cloudbrainIDs[cloudbrainId]; !ok { | |||
| cloudbrainIDs[cloudbrainId] = struct{}{} | |||
| } | |||
| } | |||
| return keysInt64(cloudbrainIDs) | |||
| } | |||
| func (actions ActionList) loadCloudbrains(e Engine) ([]*Cloudbrain, error) { | |||
| if len(actions) == 0 { | |||
| return nil, nil | |||
| } | |||
| cloudbrainIDs := actions.getCloudbrainIDs() | |||
| cloudbrainMaps := make(map[int64]*Cloudbrain, len(cloudbrainIDs)) | |||
| if len(cloudbrainIDs) == 0 { | |||
| return make([]*Cloudbrain, 0), nil | |||
| } | |||
| err := e. | |||
| In("id", cloudbrainIDs).Unscoped(). | |||
| Find(&cloudbrainMaps) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("find cloudbrain: %v", err) | |||
| } | |||
| for _, action := range actions { | |||
| cloudbrainId, _ := strconv.ParseInt(action.Content, 10, 64) | |||
| if cloudbrainId > 0 { | |||
| action.Cloudbrain = cloudbrainMaps[cloudbrainId] | |||
| } | |||
| } | |||
| return valuesCloudbrain(cloudbrainMaps), nil | |||
| } | |||
| // LoadComments loads actions' all comments | |||
| func (actions ActionList) LoadCloudbrains() ([]*Comment, error) { | |||
| return actions.loadComments(x) | |||
| } | |||
| // loadAttributes loads all attributes | |||
| func (actions ActionList) loadAttributes(e Engine) (err error) { | |||
| if _, err = actions.loadUsers(e); err != nil { | |||
| @@ -140,7 +191,7 @@ func (actions ActionList) LoadAttributes() error { | |||
| } | |||
| // LoadAllAttributes loads all attributes of the actions | |||
| // compare with LoadAttributes() ,LoadAllAttributes() loads Comment attribute | |||
| // compare with LoadAttributes() ,LoadAllAttributes() loads Comment and Cloudbrain attribute | |||
| func (actions ActionList) LoadAllAttributes() error { | |||
| return actions.loadAllAttributes(x) | |||
| } | |||
| @@ -159,5 +210,9 @@ func (actions ActionList) loadAllAttributes(e Engine) (err error) { | |||
| return | |||
| } | |||
| if _, err = actions.loadCloudbrains(e); err != nil { | |||
| return | |||
| } | |||
| return nil | |||
| } | |||
| @@ -179,6 +179,14 @@ type CloudbrainShow struct { | |||
| ComputeResource string | |||
| } | |||
| type CloudbrainShow4Action struct { | |||
| ID int64 | |||
| Type int | |||
| JobType string | |||
| DisplayJobName string | |||
| ComputeResource string | |||
| } | |||
| func (task *Cloudbrain) ToShow() *CloudbrainShow { | |||
| return &CloudbrainShow{ | |||
| ID: task.ID, | |||
| @@ -35,3 +35,10 @@ func valuesComment(m map[int64]*Comment) []*Comment { | |||
| } | |||
| return values | |||
| } | |||
| func valuesCloudbrain(m map[int64]*Cloudbrain) []*Cloudbrain { | |||
| var values = make([]*Cloudbrain, 0, len(m)) | |||
| for _, v := range m { | |||
| values = append(values, v) | |||
| } | |||
| return values | |||
| } | |||
| @@ -375,7 +375,7 @@ func (t *actionNotifier) NotifyDatasetRecommend(optUser *models.User, dataset *m | |||
| ActUser: user, | |||
| RepoID: dataset.RepoID, | |||
| Repo: dataset.Repo, | |||
| Content: fmt.Sprint(dataset.ID), | |||
| Content: fmt.Sprintf("%d|%s", dataset.ID, dataset.Title), | |||
| }) | |||
| } | |||
| if err := models.NotifyWatchers(actions...); err != nil { | |||
| @@ -390,18 +390,14 @@ func (t *actionNotifier) NotifyCreateImage(doer *models.User, image models.Image | |||
| ActUser: doer, | |||
| OpType: models.ActionCreateImage, | |||
| IsPrivate: image.IsPrivate, | |||
| Content: fmt.Sprint(image.ID), | |||
| Content: fmt.Sprintf("%d|%s", image.ID, image.Tag), | |||
| } | |||
| 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 | |||
| } | |||
| func (t *actionNotifier) NotifyImageRecommend(optUser *models.User, image *models.Image, action string) { | |||
| u, err := models.GetUserByID(image.UID) | |||
| if err != nil { | |||
| return | |||
| @@ -413,7 +409,7 @@ func (t *actionNotifier) NotifyImageRecommend(optUser *models.User, imageId int6 | |||
| ActUser: u, | |||
| OpType: models.ActionImageRecommend, | |||
| IsPrivate: false, | |||
| Content: fmt.Sprint(imageId), | |||
| Content: fmt.Sprintf("%d|%s", image.ID, image.Tag), | |||
| } | |||
| if err := models.NotifyWatchers(act); err != nil { | |||
| log.Error("notifyWatchers: %v", err) | |||
| @@ -60,6 +60,6 @@ type Notifier interface { | |||
| NotifyWechatBind(user *models.User, wechatOpenId string) | |||
| NotifyDatasetRecommend(optUser *models.User, dataset *models.Dataset, action string) | |||
| NotifyCreateImage(doer *models.User, image models.Image) | |||
| NotifyImageRecommend(optUser *models.User, imageId int64, action string) | |||
| NotifyImageRecommend(optUser *models.User, image *models.Image, action string) | |||
| NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) | |||
| } | |||
| @@ -170,7 +170,7 @@ func (*NullNotifier) NotifyDatasetRecommend(optUser *models.User, dataset *model | |||
| 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, image *models.Image, action string) { | |||
| } | |||
| func (*NullNotifier) NotifyChangeUserAvatar(user *models.User, form auth.AvatarForm) { | |||
| @@ -293,9 +293,9 @@ func NotifyCreateImage(doer *models.User, image models.Image) { | |||
| } | |||
| // NotifyDatasetRecommend | |||
| func NotifyImageRecommend(optUser *models.User, imageId int64, action string) { | |||
| func NotifyImageRecommend(optUser *models.User, image *models.Image, action string) { | |||
| for _, notifier := range notifiers { | |||
| notifier.NotifyImageRecommend(optUser, imageId, action) | |||
| notifier.NotifyImageRecommend(optUser, image, action) | |||
| } | |||
| } | |||
| @@ -26,7 +26,10 @@ func Action(ctx *context.Context) { | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.star_fail", ctx.Params(":action")))) | |||
| } else { | |||
| notification.NotifyImageRecommend(ctx.User, imageId, ctx.Params(":action")) | |||
| image, err := models.GetImageByID(imageId) | |||
| if err == nil { | |||
| notification.NotifyImageRecommend(ctx.User, image, ctx.Params(":action")) | |||
| } | |||
| ctx.JSON(http.StatusOK, models.BaseOKMessage) | |||
| } | |||
| } | |||