Reviewed-on: https://openi.pcl.ac.cn/OpenI/aiforge/pulls/3270 Reviewed-by: ychao_1983 <ychao_1983@sina.com>tags/v1.22.11.3^2
| @@ -1279,7 +1279,7 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository, opts ...Cr | |||||
| } | } | ||||
| if setting.Service.AutoWatchNewRepos { | if setting.Service.AutoWatchNewRepos { | ||||
| if err = watchRepo(ctx.e, doer.ID, repo.ID, true); err != nil { | |||||
| if err = watchRepo(ctx.e, doer.ID, repo.ID, true, ReceiveAllNotification); err != nil { | |||||
| return fmt.Errorf("watchRepo: %v", err) | return fmt.Errorf("watchRepo: %v", err) | ||||
| } | } | ||||
| } | } | ||||
| @@ -24,6 +24,14 @@ const ( | |||||
| RepoWatchModeAuto // 3 | RepoWatchModeAuto // 3 | ||||
| ) | ) | ||||
| // NotifyType specifies what kind of watch the user has on a repository | |||||
| type NotifyType int8 | |||||
| const ( | |||||
| RejectAllNotification NotifyType = 0 | |||||
| ReceiveAllNotification NotifyType = 9 | |||||
| ) | |||||
| var ActionChan = make(chan *Action, 200) | var ActionChan = make(chan *Action, 200) | ||||
| var ActionChan4Task = make(chan Action, 200) | var ActionChan4Task = make(chan Action, 200) | ||||
| @@ -34,6 +42,7 @@ type Watch struct { | |||||
| RepoID int64 `xorm:"UNIQUE(watch)"` | RepoID int64 `xorm:"UNIQUE(watch)"` | ||||
| Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` | Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` | ||||
| CreatedUnix int64 `xorm:"created"` | CreatedUnix int64 `xorm:"created"` | ||||
| NotifyType NotifyType `xorm:"SMALLINT NOT NULL DEFAULT 0"` | |||||
| } | } | ||||
| // getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found | // getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found | ||||
| @@ -60,8 +69,20 @@ func IsWatching(userID, repoID int64) bool { | |||||
| return err == nil && isWatchMode(watch.Mode) | return err == nil && isWatchMode(watch.Mode) | ||||
| } | } | ||||
| // GetWatchNotifyType | |||||
| func GetWatchNotifyType(userID, repoID int64) NotifyType { | |||||
| watch, err := getWatch(x, userID, repoID) | |||||
| if err != nil { | |||||
| return RejectAllNotification | |||||
| } | |||||
| return watch.NotifyType | |||||
| } | |||||
| func watchRepoMode(e Engine, watch Watch, mode RepoWatchMode) (err error) { | func watchRepoMode(e Engine, watch Watch, mode RepoWatchMode) (err error) { | ||||
| if watch.Mode == mode { | if watch.Mode == mode { | ||||
| if _, err := e.ID(watch.ID).Cols("notify_type").Update(watch); err != nil { | |||||
| return err | |||||
| } | |||||
| return nil | return nil | ||||
| } | } | ||||
| if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) { | if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) { | ||||
| @@ -109,7 +130,7 @@ func WatchRepoMode(userID, repoID int64, mode RepoWatchMode) (err error) { | |||||
| return watchRepoMode(x, watch, mode) | return watchRepoMode(x, watch, mode) | ||||
| } | } | ||||
| func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { | |||||
| func watchRepo(e Engine, userID, repoID int64, doWatch bool, notifyTypes ...NotifyType) (err error) { | |||||
| var watch Watch | var watch Watch | ||||
| if watch, err = getWatch(e, userID, repoID); err != nil { | if watch, err = getWatch(e, userID, repoID); err != nil { | ||||
| return err | return err | ||||
| @@ -119,14 +140,19 @@ func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { | |||||
| } else if !doWatch { | } else if !doWatch { | ||||
| err = watchRepoMode(e, watch, RepoWatchModeNone) | err = watchRepoMode(e, watch, RepoWatchModeNone) | ||||
| } else { | } else { | ||||
| notifyType := RejectAllNotification | |||||
| if len(notifyTypes) > 0 { | |||||
| notifyType = notifyTypes[0] | |||||
| } | |||||
| watch.NotifyType = notifyType | |||||
| err = watchRepoMode(e, watch, RepoWatchModeNormal) | err = watchRepoMode(e, watch, RepoWatchModeNormal) | ||||
| } | } | ||||
| return err | return err | ||||
| } | } | ||||
| // WatchRepo watch or unwatch repository. | // WatchRepo watch or unwatch repository. | ||||
| func WatchRepo(userID, repoID int64, watch bool) (err error) { | |||||
| return watchRepo(x, userID, repoID, watch) | |||||
| func WatchRepo(userID, repoID int64, watch bool, notifyType ...NotifyType) (err error) { | |||||
| return watchRepo(x, userID, repoID, watch, notifyType...) | |||||
| } | } | ||||
| func getWatchers(e Engine, repoID int64) ([]*Watch, error) { | func getWatchers(e Engine, repoID int64) ([]*Watch, error) { | ||||
| @@ -156,6 +182,7 @@ func getRepoWatchersIDs(e Engine, repoID int64) ([]int64, error) { | |||||
| return ids, e.Table("watch"). | return ids, e.Table("watch"). | ||||
| Where("watch.repo_id=?", repoID). | Where("watch.repo_id=?", repoID). | ||||
| And("watch.mode<>?", RepoWatchModeDont). | And("watch.mode<>?", RepoWatchModeDont). | ||||
| And("watch.notify_type > ?", RejectAllNotification). | |||||
| Select("user_id"). | Select("user_id"). | ||||
| Find(&ids) | Find(&ids) | ||||
| } | } | ||||
| @@ -474,6 +474,7 @@ func RepoAssignment() macaron.Handler { | |||||
| if ctx.IsSigned { | if ctx.IsSigned { | ||||
| ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID) | ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID) | ||||
| ctx.Data["WatchNotifyType"] = models.GetWatchNotifyType(ctx.User.ID, repo.ID) | |||||
| ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID) | ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID) | ||||
| ctx.Data["IsStaringDataset"] = models.IsDatasetStaringByRepoId(ctx.User.ID, repo.ID) | ctx.Data["IsStaringDataset"] = models.IsDatasetStaringByRepoId(ctx.User.ID, repo.ID) | ||||
| @@ -1394,6 +1394,11 @@ star = Star | |||||
| fork = Fork | fork = Fork | ||||
| download_archive = Download Repository | download_archive = Download Repository | ||||
| star_fail=Failed to %s the dataset. | star_fail=Failed to %s the dataset. | ||||
| watched=Watched | |||||
| notWatched=Not watched | |||||
| un_watch=Unwatch | |||||
| watch_all=Watch all | |||||
| watch_no_notify=Watch but not notify | |||||
| no_desc = No Description | no_desc = No Description | ||||
| no_label = No labels | no_label = No labels | ||||
| @@ -1411,6 +1411,11 @@ star=点赞 | |||||
| fork=派生 | fork=派生 | ||||
| download_archive=下载此项目 | download_archive=下载此项目 | ||||
| star_fail=%s失败。 | star_fail=%s失败。 | ||||
| watched=已关注 | |||||
| notWatched=未关注 | |||||
| un_watch=不关注 | |||||
| watch_all=关注所有动态 | |||||
| watch_no_notify=关注但不提醒动态 | |||||
| no_desc=暂无描述 | no_desc=暂无描述 | ||||
| @@ -414,7 +414,9 @@ func Action(ctx *context.Context) { | |||||
| var err error | var err error | ||||
| switch ctx.Params(":action") { | switch ctx.Params(":action") { | ||||
| case "watch": | case "watch": | ||||
| err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true) | |||||
| err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true, models.ReceiveAllNotification) | |||||
| case "watch_but_reject": | |||||
| err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true, models.RejectAllNotification) | |||||
| case "unwatch": | case "unwatch": | ||||
| err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false) | err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false) | ||||
| case "star": | case "star": | ||||
| @@ -51,6 +51,49 @@ | |||||
| </div> | </div> | ||||
| {{if not .IsBeingCreated}} | {{if not .IsBeingCreated}} | ||||
| <div class="repo-buttons"> | <div class="repo-buttons"> | ||||
| <div class="ui labeled button" tabindex="0"> | |||||
| <div class="ui compact basic button" onclick="$('.__watch_btn__').dropdown('show')"> | |||||
| <i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.watched"}}{{else}}{{$.i18n.Tr "repo.notWatched"}}{{end}} | |||||
| <i class="dropdown icon" style="margin:0 -8px 0 4px"></i> | |||||
| <div class="ui dropdown floating __watch_btn__" onclick="event.stopPropagation();"> | |||||
| <div class="text" style="display:none;"></div> | |||||
| {{$WatchNotifyType := or $.WatchNotifyType 0}} | |||||
| <div class="menu" style="margin-left:-64px;"> | |||||
| <div class="item {{if not $.IsWatchingRepo}}active selected{{end}}"> | |||||
| <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/unwatch?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" style="border:none;background:transparent;width:100%;text-align:left;font-weight:inherit;cursor:pointer;"> | |||||
| <i class="check icon" style="{{if $.IsWatchingRepo}}opacity:0{{end}}"></i> | |||||
| {{$.i18n.Tr "repo.un_watch"}} | |||||
| </button> | |||||
| </form> | |||||
| </div> | |||||
| <div class="item {{if and $.IsWatchingRepo (eq $WatchNotifyType 9)}}active selected{{end}}"> | |||||
| <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/watch?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" style="border:none;background:transparent;width:100%;text-align:left;font-weight:inherit;cursor:pointer;"> | |||||
| <i class="check icon" style="{{if not (and $.IsWatchingRepo (eq $WatchNotifyType 9))}}opacity:0{{end}}"></i> | |||||
| {{$.i18n.Tr "repo.watch_all"}} | |||||
| </button> | |||||
| </form> | |||||
| </div> | |||||
| <div class="item {{if and $.IsWatchingRepo (eq $WatchNotifyType 0)}}active selected{{end}}"> | |||||
| <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/watch_but_reject?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" style="border:none;background:transparent;width:100%;text-align:left;font-weight:inherit;cursor:pointer;"> | |||||
| <i class="check icon" style="{{if not (and $.IsWatchingRepo (eq $WatchNotifyType 0))}}opacity:0{{end}}"></i> | |||||
| {{$.i18n.Tr "repo.watch_no_notify"}} | |||||
| </button> | |||||
| </form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="ui basic label" href="{{.Link}}/watchers"> | |||||
| {{.NumWatches}} | |||||
| </a> | |||||
| </div> | |||||
| <!-- | |||||
| <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> | <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| <div class="ui labeled button" tabindex="0"> | <div class="ui labeled button" tabindex="0"> | ||||
| @@ -61,7 +104,7 @@ | |||||
| {{.NumWatches}} | {{.NumWatches}} | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| </form> | |||||
| </form> --> | |||||
| <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> | <form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| <div class="ui labeled button" tabindex="0"> | <div class="ui labeled button" tabindex="0"> | ||||