mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-08 22:13:26 +09:00
chore: fix repo watch (#38921)
This commit is contained in:
@@ -13,9 +13,9 @@ import (
|
|||||||
|
|
||||||
func AddWatchOptions(_ context.Context, x base.EngineMigration) error {
|
func AddWatchOptions(_ context.Context, x base.EngineMigration) error {
|
||||||
type Watch struct {
|
type Watch struct {
|
||||||
PullRequests bool `xorm:"NOT NULL DEFAULT true"`
|
IncludePullRequests bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
Issues bool `xorm:"NOT NULL DEFAULT true"`
|
IncludeIssues bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
Releases bool `xorm:"NOT NULL DEFAULT true"`
|
IncludeReleases bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
}
|
}
|
||||||
_, err := x.SyncWithOptions(xorm.SyncOptions{
|
_, err := x.SyncWithOptions(xorm.SyncOptions{
|
||||||
IgnoreConstrains: true,
|
IgnoreConstrains: true,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func TestCreateOrUpdateIssueNotificationsIgnored(t *testing.T) {
|
|||||||
// user 4 watches repo 1 and would be notified about issue 1
|
// user 4 watches repo 1 and would be notified about issue 1
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||||
assert.NoError(t, repo_model.WatchIgnoreRepo(t.Context(), user, repo))
|
assert.NoError(t, repo_model.WatchRepoWithOptions(t.Context(), user, repo, repo_model.WatchOptions{Mode: repo_model.WatchModeDont}))
|
||||||
|
|
||||||
notified, err := activities_model.CreateOrUpdateIssueNotifications(t.Context(), 1, 0, 2, 0)
|
notified, err := activities_model.CreateOrUpdateIssueNotifications(t.Context(), 1, 0, 2, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func CheckIssueWatch(ctx context.Context, user *user_model.User, issue *Issue) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if repo_model.IsWatchMode(w.Mode) && util.Iif(issue.IsPull, w.PullRequests, w.Issues) {
|
if repo_model.IsWatchModeWatching(w.Mode) && util.Iif(issue.IsPull, w.IncludePullRequests, w.IncludeIssues) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
return IsUserParticipantsOfIssue(ctx, user, issue), nil
|
return IsUserParticipantsOfIssue(ctx, user, issue), nil
|
||||||
|
|||||||
@@ -67,11 +67,11 @@ func TestWatchRepo(t *testing.T) {
|
|||||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3})
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|
||||||
assert.NoError(t, WatchRepo(t.Context(), user, repo, true))
|
assert.NoError(t, WatchRepoAuto(t.Context(), user, repo, true))
|
||||||
unittest.AssertExistsAndLoadBean(t, &Watch{RepoID: repo.ID, UserID: user.ID})
|
unittest.AssertExistsAndLoadBean(t, &Watch{RepoID: repo.ID, UserID: user.ID})
|
||||||
unittest.CheckConsistencyFor(t, &Repository{ID: repo.ID})
|
unittest.CheckConsistencyFor(t, &Repository{ID: repo.ID})
|
||||||
|
|
||||||
assert.NoError(t, WatchRepo(t.Context(), user, repo, false))
|
assert.NoError(t, WatchRepoAuto(t.Context(), user, repo, false))
|
||||||
unittest.AssertNotExistsBean(t, &Watch{RepoID: repo.ID, UserID: user.ID})
|
unittest.AssertNotExistsBean(t, &Watch{RepoID: repo.ID, UserID: user.ID})
|
||||||
unittest.CheckConsistencyFor(t, &Repository{ID: repo.ID})
|
unittest.CheckConsistencyFor(t, &Repository{ID: repo.ID})
|
||||||
}
|
}
|
||||||
|
|||||||
+83
-71
@@ -18,14 +18,11 @@ import (
|
|||||||
type WatchMode int8
|
type WatchMode int8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// WatchModeNone don't watch
|
WatchModeNone WatchMode = iota // 0 watch nothing unless mentioned
|
||||||
WatchModeNone WatchMode = iota // 0
|
|
||||||
// WatchModeNormal watch repository (from other sources)
|
WatchModeNormal // 1 proactively watching (all or custom)
|
||||||
WatchModeNormal // 1
|
WatchModeDont // 2 ignore the repo
|
||||||
// WatchModeDont explicit don't auto-watch
|
WatchModeAuto // 3 automatically watching (from AutoWatchOnChanges)
|
||||||
WatchModeDont // 2
|
|
||||||
// WatchModeAuto watch repository (from AutoWatchOnChanges)
|
|
||||||
WatchModeAuto // 3
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WatchType is the `watch` column gating one kind of notification
|
// WatchType is the `watch` column gating one kind of notification
|
||||||
@@ -39,15 +36,16 @@ const (
|
|||||||
|
|
||||||
// Watch is connection request for receiving repository notification.
|
// Watch is connection request for receiving repository notification.
|
||||||
type Watch struct {
|
type Watch struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UserID int64 `xorm:"UNIQUE(watch)"`
|
UserID int64 `xorm:"UNIQUE(watch)"`
|
||||||
RepoID int64 `xorm:"UNIQUE(watch)"`
|
RepoID int64 `xorm:"UNIQUE(watch)"`
|
||||||
Mode WatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"`
|
Mode WatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"`
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
PullRequests bool `xorm:"NOT NULL DEFAULT true"`
|
|
||||||
Issues bool `xorm:"NOT NULL DEFAULT true"`
|
IncludePullRequests bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
Releases bool `xorm:"NOT NULL DEFAULT true"`
|
IncludeIssues bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
|
IncludeReleases bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -61,7 +59,7 @@ func GetWatch(ctx context.Context, userID, repoID int64) (*Watch, error) {
|
|||||||
return watch, err
|
return watch, err
|
||||||
}
|
}
|
||||||
if watch == nil { // the dummy record must mirror the column defaults
|
if watch == nil { // the dummy record must mirror the column defaults
|
||||||
watch = &Watch{UserID: userID, RepoID: repoID, PullRequests: true, Issues: true, Releases: true}
|
watch = &Watch{UserID: userID, RepoID: repoID, IncludePullRequests: true, IncludeIssues: true, IncludeReleases: true}
|
||||||
}
|
}
|
||||||
if !has {
|
if !has {
|
||||||
watch.Mode = WatchModeNone
|
watch.Mode = WatchModeNone
|
||||||
@@ -76,12 +74,16 @@ func (w *Watch) IsIgnoring() bool {
|
|||||||
|
|
||||||
// IsWatching reports whether the watch counts the user as a watcher of the repository
|
// IsWatching reports whether the watch counts the user as a watcher of the repository
|
||||||
func (w *Watch) IsWatching() bool {
|
func (w *Watch) IsWatching() bool {
|
||||||
return IsWatchMode(w.Mode)
|
return IsWatchModeWatching(w.Mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWatchingAll reports whether every event is enabled, which is the "all activity" mode
|
// IsWatchingAll reports whether every event is enabled, which is the "all activity" mode
|
||||||
func (w *Watch) IsWatchingAll() bool {
|
func (w *Watch) IsWatchingAll() bool {
|
||||||
return w.PullRequests && w.Issues && w.Releases
|
return w.IncludePullRequests && w.IncludeIssues && w.IncludeReleases
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watch) IsWatchingAny() bool {
|
||||||
|
return w.IncludePullRequests || w.IncludeIssues || w.IncludeReleases
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectedMode returns the mode the user picked in the watch menu
|
// SelectedMode returns the mode the user picked in the watch menu
|
||||||
@@ -89,7 +91,7 @@ func (w *Watch) SelectedMode() string {
|
|||||||
switch {
|
switch {
|
||||||
case w.IsIgnoring():
|
case w.IsIgnoring():
|
||||||
return "ignore"
|
return "ignore"
|
||||||
case !IsWatchMode(w.Mode), !(w.PullRequests || w.Issues || w.Releases):
|
case !IsWatchModeWatching(w.Mode), !w.IsWatchingAny():
|
||||||
return "participate" // also the default while there is no watch row
|
return "participate" // also the default while there is no watch row
|
||||||
case w.IsWatchingAll():
|
case w.IsWatchingAll():
|
||||||
return "all"
|
return "all"
|
||||||
@@ -97,110 +99,105 @@ func (w *Watch) SelectedMode() string {
|
|||||||
return "custom"
|
return "custom"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWatchMode Decodes watchability of WatchMode
|
// IsWatchModeWatching Decodes watchability of WatchMode
|
||||||
func IsWatchMode(mode WatchMode) bool {
|
func IsWatchModeWatching(mode WatchMode) bool {
|
||||||
return mode != WatchModeNone && mode != WatchModeDont
|
return mode != WatchModeNone && mode != WatchModeDont
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWatching checks if user has watched given repository.
|
// IsWatchingRepo checks if user has watched given repository.
|
||||||
func IsWatching(ctx context.Context, userID, repoID int64) bool {
|
func IsWatchingRepo(ctx context.Context, userID, repoID int64) bool {
|
||||||
watch, err := GetWatch(ctx, userID, repoID)
|
watch, err := GetWatch(ctx, userID, repoID)
|
||||||
return err == nil && IsWatchMode(watch.Mode)
|
return err == nil && IsWatchModeWatching(watch.Mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func watchRepoMode(ctx context.Context, watch *Watch, mode WatchMode) (err error) {
|
func watchRepoByMode(ctx context.Context, watch *Watch, mode WatchMode) (err error) {
|
||||||
if watch.Mode == mode {
|
if watch.Mode == mode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if mode == WatchModeAuto && (watch.Mode == WatchModeDont || IsWatchMode(watch.Mode)) {
|
if mode == WatchModeAuto && (watch.Mode == WatchModeDont || IsWatchModeWatching(watch.Mode)) {
|
||||||
// Don't auto watch if already watching or deliberately not watching
|
// Don't auto watch if already watching or deliberately not watching
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
hadrec := watch.Mode != WatchModeNone
|
hadWatchModeSet := watch.Mode != WatchModeNone
|
||||||
needsrec := mode != WatchModeNone
|
needSetWatchMode := mode != WatchModeNone
|
||||||
repodiff := 0
|
repoWatchDelta := 0
|
||||||
|
|
||||||
if IsWatchMode(mode) && !IsWatchMode(watch.Mode) {
|
if IsWatchModeWatching(mode) && !IsWatchModeWatching(watch.Mode) {
|
||||||
repodiff = 1
|
repoWatchDelta = 1
|
||||||
} else if !IsWatchMode(mode) && IsWatchMode(watch.Mode) {
|
} else if !IsWatchModeWatching(mode) && IsWatchModeWatching(watch.Mode) {
|
||||||
repodiff = -1
|
repoWatchDelta = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
if repodiff == 1 { // starting to watch resets the options, otherwise a custom selection survives
|
if repoWatchDelta == 1 { // starting to watch resets the options, otherwise a custom selection survives
|
||||||
watch.PullRequests, watch.Issues, watch.Releases = true, true, true
|
watch.IncludePullRequests, watch.IncludeIssues, watch.IncludeReleases = true, true, true
|
||||||
}
|
}
|
||||||
watch.Mode = mode
|
watch.Mode = mode
|
||||||
|
|
||||||
if !hadrec && needsrec {
|
if !hadWatchModeSet && needSetWatchMode {
|
||||||
if err = db.Insert(ctx, watch); err != nil {
|
if err = db.Insert(ctx, watch); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if needsrec {
|
} else if needSetWatchMode {
|
||||||
if _, err := db.GetEngine(ctx).ID(watch.ID).AllCols().Update(watch); err != nil {
|
if _, err := db.GetEngine(ctx).ID(watch.ID).AllCols().Update(watch); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if _, err = db.DeleteByID[Watch](ctx, watch.ID); err != nil {
|
} else if _, err = db.DeleteByID[Watch](ctx, watch.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if repodiff != 0 {
|
if repoWatchDelta != 0 {
|
||||||
_, err = db.GetEngine(ctx).Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repodiff, watch.RepoID)
|
_, err = db.GetEngine(ctx).Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repoWatchDelta, watch.RepoID)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchRepo watch or unwatch repository.
|
// WatchRepoAuto watch or unwatch repository.
|
||||||
func WatchRepo(ctx context.Context, doer *user_model.User, repo *Repository, doWatch bool) error {
|
func WatchRepoAuto(ctx context.Context, doer *user_model.User, repo *Repository, doWatch bool) error {
|
||||||
watch, err := GetWatch(ctx, doer.ID, repo.ID)
|
watch, err := GetWatch(ctx, doer.ID, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !doWatch && watch.Mode == WatchModeAuto {
|
if !doWatch && watch.Mode == WatchModeAuto {
|
||||||
return watchRepoMode(ctx, watch, WatchModeDont)
|
return watchRepoByMode(ctx, watch, WatchModeDont)
|
||||||
} else if !doWatch {
|
} else if !doWatch {
|
||||||
return watchRepoMode(ctx, watch, WatchModeNone)
|
return watchRepoByMode(ctx, watch, WatchModeNone)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user_model.IsUserBlockedBy(ctx, doer, repo.OwnerID) {
|
if user_model.IsUserBlockedBy(ctx, doer, repo.OwnerID) {
|
||||||
return user_model.ErrBlockedUser
|
return user_model.ErrBlockedUser
|
||||||
}
|
}
|
||||||
|
|
||||||
return watchRepoMode(ctx, watch, WatchModeNormal)
|
return watchRepoByMode(ctx, watch, WatchModeNormal)
|
||||||
}
|
|
||||||
|
|
||||||
// WatchIgnoreRepo mutes the repository (unwatch), so nothing about it reaches the user.
|
|
||||||
func WatchIgnoreRepo(ctx context.Context, doer *user_model.User, repo *Repository) error {
|
|
||||||
watch, err := GetWatch(ctx, doer.ID, repo.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return watchRepoMode(ctx, watch, WatchModeDont)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type WatchOptions struct {
|
type WatchOptions struct {
|
||||||
PullRequests bool
|
Mode WatchMode
|
||||||
Issues bool
|
|
||||||
Releases bool
|
WatchPullRequests bool
|
||||||
|
WatchIssues bool
|
||||||
|
WatchReleases bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchRepoWithOptions starts watching the repository and subscribes to the given events
|
// WatchRepoWithOptions starts watching the repository and subscribes to the given events
|
||||||
func WatchRepoWithOptions(ctx context.Context, doer *user_model.User, repo *Repository, opts WatchOptions) error {
|
func WatchRepoWithOptions(ctx context.Context, doer *user_model.User, repo *Repository, opts WatchOptions) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
if err := WatchRepo(ctx, doer, repo, true); err != nil {
|
watch, err := GetWatch(ctx, doer.ID, repo.ID)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return SetWatchOptions(ctx, doer.ID, repo.ID, opts)
|
err = watchRepoByMode(ctx, watch, opts.Mode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if opts.Mode == WatchModeNormal {
|
||||||
|
_, err = db.GetEngine(ctx).Where("user_id=? AND repo_id=?", doer.ID, repo.ID).
|
||||||
|
Cols("include_pull_requests", "include_issues", "include_releases").
|
||||||
|
Update(&Watch{IncludePullRequests: opts.WatchPullRequests, IncludeIssues: opts.WatchIssues, IncludeReleases: opts.WatchReleases})
|
||||||
|
}
|
||||||
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWatchOptions updates the per-event options of a watch, callers must run WatchRepo first
|
|
||||||
func SetWatchOptions(ctx context.Context, userID, repoID int64, opts WatchOptions) error {
|
|
||||||
_, err := db.GetEngine(ctx).Where("user_id=? AND repo_id=?", userID, repoID).
|
|
||||||
Cols(string(WatchPullRequests), string(WatchIssues), string(WatchReleases)).
|
|
||||||
Update(&Watch{PullRequests: opts.PullRequests, Issues: opts.Issues, Releases: opts.Releases})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserWatches returns the watches of one user, keyed by repository ID
|
// GetUserWatches returns the watches of one user, keyed by repository ID
|
||||||
func GetUserWatches(ctx context.Context, userID int64, repoIDs []int64) (map[int64]*Watch, error) {
|
func GetUserWatches(ctx context.Context, userID int64, repoIDs []int64) (map[int64]*Watch, error) {
|
||||||
if len(repoIDs) == 0 {
|
if len(repoIDs) == 0 {
|
||||||
@@ -225,7 +222,11 @@ func GetWatchers(ctx context.Context, repoID int64) ([]*Watch, error) {
|
|||||||
watches := make([]*Watch, 0, 10)
|
watches := make([]*Watch, 0, 10)
|
||||||
return watches, db.GetEngine(ctx).Where("`watch`.repo_id=?", repoID).
|
return watches, db.GetEngine(ctx).Where("`watch`.repo_id=?", repoID).
|
||||||
And("`watch`.mode<>?", WatchModeDont).
|
And("`watch`.mode<>?", WatchModeDont).
|
||||||
And(builder.Or(builder.Eq{"`watch`.pull_requests": true}, builder.Eq{"`watch`.issues": true}, builder.Eq{"`watch`.releases": true})).
|
And(builder.Or(
|
||||||
|
builder.Eq{"`watch`.include_pull_requests": true},
|
||||||
|
builder.Eq{"`watch`.include_issues": true},
|
||||||
|
builder.Eq{"`watch`.include_releases": true},
|
||||||
|
)).
|
||||||
And("`user`.is_active=?", true).
|
And("`user`.is_active=?", true).
|
||||||
And("`user`.prohibit_login=?", false).
|
And("`user`.prohibit_login=?", false).
|
||||||
Join("INNER", "`user`", "`user`.id = `watch`.user_id").
|
Join("INNER", "`user`", "`user`.id = `watch`.user_id").
|
||||||
@@ -247,10 +248,21 @@ func GetRepoIgnorersIDs(ctx context.Context, repoID int64) ([]int64, error) {
|
|||||||
// User permissions must be verified elsewhere if required
|
// User permissions must be verified elsewhere if required
|
||||||
func GetRepoWatchersIDs(ctx context.Context, repoID int64, watchType WatchType) ([]int64, error) {
|
func GetRepoWatchersIDs(ctx context.Context, repoID int64, watchType WatchType) ([]int64, error) {
|
||||||
ids := make([]int64, 0, 64)
|
ids := make([]int64, 0, 64)
|
||||||
|
var watchColName string
|
||||||
|
switch watchType {
|
||||||
|
case WatchPullRequests:
|
||||||
|
watchColName = "include_pull_requests"
|
||||||
|
case WatchIssues:
|
||||||
|
watchColName = "include_issues"
|
||||||
|
case WatchReleases:
|
||||||
|
watchColName = "include_releases"
|
||||||
|
default:
|
||||||
|
panic("invalid WatchType")
|
||||||
|
}
|
||||||
return ids, db.GetEngine(ctx).Table("watch").
|
return ids, db.GetEngine(ctx).Table("watch").
|
||||||
Where("watch.repo_id=?", repoID).
|
Where("watch.repo_id=?", repoID).
|
||||||
And("watch.mode<>?", WatchModeDont).
|
And("watch.mode<>?", WatchModeDont).
|
||||||
And(builder.Eq{"watch." + string(watchType): true}).
|
And(builder.Eq{watchColName: true}).
|
||||||
Select("user_id").
|
Select("user_id").
|
||||||
Find(&ids)
|
Find(&ids)
|
||||||
}
|
}
|
||||||
@@ -283,7 +295,7 @@ func WatchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error
|
|||||||
if watch.Mode != WatchModeNone {
|
if watch.Mode != WatchModeNone {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return watchRepoMode(ctx, watch, WatchModeAuto)
|
return watchRepoByMode(ctx, watch, WatchModeAuto)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearRepoWatches clears all watches for a repository and from the user that watched it.
|
// ClearRepoWatches clears all watches for a repository and from the user that watched it.
|
||||||
|
|||||||
+14
-14
@@ -19,13 +19,13 @@ import (
|
|||||||
func TestIsWatching(t *testing.T) {
|
func TestIsWatching(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
assert.True(t, repo_model.IsWatching(t.Context(), 1, 1))
|
assert.True(t, repo_model.IsWatchingRepo(t.Context(), 1, 1))
|
||||||
assert.True(t, repo_model.IsWatching(t.Context(), 4, 1))
|
assert.True(t, repo_model.IsWatchingRepo(t.Context(), 4, 1))
|
||||||
assert.True(t, repo_model.IsWatching(t.Context(), 11, 1))
|
assert.True(t, repo_model.IsWatchingRepo(t.Context(), 11, 1))
|
||||||
|
|
||||||
assert.False(t, repo_model.IsWatching(t.Context(), 1, 5))
|
assert.False(t, repo_model.IsWatchingRepo(t.Context(), 1, 5))
|
||||||
assert.False(t, repo_model.IsWatching(t.Context(), 8, 1))
|
assert.False(t, repo_model.IsWatchingRepo(t.Context(), 8, 1))
|
||||||
assert.False(t, repo_model.IsWatching(t.Context(), unittest.NonexistentID, unittest.NonexistentID))
|
assert.False(t, repo_model.IsWatchingRepo(t.Context(), unittest.NonexistentID, unittest.NonexistentID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetWatchers(t *testing.T) {
|
func TestGetWatchers(t *testing.T) {
|
||||||
@@ -109,7 +109,7 @@ func TestWatchIfAuto(t *testing.T) {
|
|||||||
assert.Len(t, watchers, prevCount+1)
|
assert.Len(t, watchers, prevCount+1)
|
||||||
|
|
||||||
// Should remove watch, inhibit from adding auto
|
// Should remove watch, inhibit from adding auto
|
||||||
assert.NoError(t, repo_model.WatchRepo(t.Context(), user12, repo, false))
|
assert.NoError(t, repo_model.WatchRepoAuto(t.Context(), user12, repo, false))
|
||||||
watchers, err = repo_model.GetRepoWatchers(t.Context(), repo.ID, db.ListOptions{Page: 1})
|
watchers, err = repo_model.GetRepoWatchers(t.Context(), repo.ID, db.ListOptions{Page: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, watchers, prevCount)
|
assert.Len(t, watchers, prevCount)
|
||||||
@@ -145,7 +145,7 @@ func TestWatchOptions(t *testing.T) {
|
|||||||
// repo 1 is watched by users 1, 4, 9 and 11, all with every event enabled
|
// repo 1 is watched by users 1, 4, 9 and 11, all with every event enabled
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
assert.NoError(t, repo_model.SetWatchOptions(t.Context(), user.ID, repo.ID, repo_model.WatchOptions{PullRequests: true}))
|
assert.NoError(t, repo_model.WatchRepoWithOptions(t.Context(), user, repo, repo_model.WatchOptions{Mode: repo_model.WatchModeNormal, WatchPullRequests: true}))
|
||||||
|
|
||||||
for watchType, expected := range map[repo_model.WatchType][]int64{
|
for watchType, expected := range map[repo_model.WatchType][]int64{
|
||||||
repo_model.WatchPullRequests: {1, 4, 9, 11},
|
repo_model.WatchPullRequests: {1, 4, 9, 11},
|
||||||
@@ -160,11 +160,11 @@ func TestWatchOptions(t *testing.T) {
|
|||||||
// the options of one user must not show up for another
|
// the options of one user must not show up for another
|
||||||
watches, err := repo_model.GetUserWatches(t.Context(), 4, []int64{repo.ID})
|
watches, err := repo_model.GetUserWatches(t.Context(), 4, []int64{repo.ID})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, watches[repo.ID].Issues)
|
assert.True(t, watches[repo.ID].IncludeIssues)
|
||||||
|
|
||||||
// watching again resets a custom selection
|
// watching again resets a custom selection
|
||||||
assert.NoError(t, repo_model.WatchRepo(t.Context(), user, repo, false))
|
assert.NoError(t, repo_model.WatchRepoAuto(t.Context(), user, repo, false))
|
||||||
assert.NoError(t, repo_model.WatchRepo(t.Context(), user, repo, true))
|
assert.NoError(t, repo_model.WatchRepoAuto(t.Context(), user, repo, true))
|
||||||
watch, err := repo_model.GetWatch(t.Context(), user.ID, repo.ID)
|
watch, err := repo_model.GetWatch(t.Context(), user.ID, repo.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, watch.IsWatchingAll())
|
assert.True(t, watch.IsWatchingAll())
|
||||||
@@ -172,9 +172,9 @@ func TestWatchOptions(t *testing.T) {
|
|||||||
|
|
||||||
func TestWatchSelectedMode(t *testing.T) {
|
func TestWatchSelectedMode(t *testing.T) {
|
||||||
// a user without a watch row gets the dummy record, whose flags are the column defaults
|
// a user without a watch row gets the dummy record, whose flags are the column defaults
|
||||||
assert.Equal(t, "participate", (&repo_model.Watch{Mode: repo_model.WatchModeNone, PullRequests: true, Issues: true, Releases: true}).SelectedMode())
|
assert.Equal(t, "participate", (&repo_model.Watch{Mode: repo_model.WatchModeNone, IncludePullRequests: true, IncludeIssues: true, IncludeReleases: true}).SelectedMode())
|
||||||
assert.Equal(t, "participate", (&repo_model.Watch{Mode: repo_model.WatchModeNormal}).SelectedMode())
|
assert.Equal(t, "participate", (&repo_model.Watch{Mode: repo_model.WatchModeNormal}).SelectedMode())
|
||||||
assert.Equal(t, "ignore", (&repo_model.Watch{Mode: repo_model.WatchModeDont}).SelectedMode())
|
assert.Equal(t, "ignore", (&repo_model.Watch{Mode: repo_model.WatchModeDont}).SelectedMode())
|
||||||
assert.Equal(t, "custom", (&repo_model.Watch{Mode: repo_model.WatchModeNormal, Issues: true}).SelectedMode())
|
assert.Equal(t, "custom", (&repo_model.Watch{Mode: repo_model.WatchModeNormal, IncludeIssues: true}).SelectedMode())
|
||||||
assert.Equal(t, "all", (&repo_model.Watch{Mode: repo_model.WatchModeAuto, PullRequests: true, Issues: true, Releases: true}).SelectedMode())
|
assert.Equal(t, "all", (&repo_model.Watch{Mode: repo_model.WatchModeAuto, IncludePullRequests: true, IncludeIssues: true, IncludeReleases: true}).SelectedMode())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func IsWatching(ctx *context.APIContext) {
|
|||||||
// "404":
|
// "404":
|
||||||
// description: User is not watching this repo or repo do not exist
|
// description: User is not watching this repo or repo do not exist
|
||||||
|
|
||||||
if repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
|
if repo_model.IsWatchingRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
|
||||||
ctx.JSON(http.StatusOK, api.WatchInfo{
|
ctx.JSON(http.StatusOK, api.WatchInfo{
|
||||||
Subscribed: true,
|
Subscribed: true,
|
||||||
Ignored: false,
|
Ignored: false,
|
||||||
@@ -170,7 +170,7 @@ func Watch(ctx *context.APIContext) {
|
|||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, true)
|
err := repo_model.WatchRepoAuto(ctx, ctx.Doer, ctx.Repo.Repository, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, user_model.ErrBlockedUser) {
|
if errors.Is(err, user_model.ErrBlockedUser) {
|
||||||
ctx.APIError(http.StatusForbidden, err.Error())
|
ctx.APIError(http.StatusForbidden, err.Error())
|
||||||
@@ -211,7 +211,7 @@ func Unwatch(ctx *context.APIContext) {
|
|||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
|
err := repo_model.WatchRepoAuto(ctx, ctx.Doer, ctx.Repo.Repository, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.APIErrorInternal(err)
|
ctx.APIErrorInternal(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ func CreatePost(ctx *context.Context) {
|
|||||||
handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
|
handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleActionError(ctx *context.Context, err error) {
|
func handleRepoActionError(ctx *context.Context, err error) {
|
||||||
var errLimitReached repo_service.LimitReachedError
|
var errLimitReached repo_service.LimitReachedError
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, user_model.ErrBlockedUser):
|
case errors.Is(err, user_model.ErrBlockedUser):
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const tplStarUnstar templates.TplName = "repo/header/star"
|
|||||||
func ActionStar(ctx *context.Context) {
|
func ActionStar(ctx *context.Context) {
|
||||||
err := repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, ctx.PathParam("action") == "star")
|
err := repo_model.StarRepo(ctx, ctx.Doer, ctx.Repo.Repository, ctx.PathParam("action") == "star")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleActionError(ctx, err)
|
handleRepoActionError(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func acceptTransfer(ctx *context.Context) {
|
|||||||
ctx.JSONRedirect(ctx.Repo.Repository.Link())
|
ctx.JSONRedirect(ctx.Repo.Repository.Link())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
handleActionError(ctx, err)
|
handleRepoActionError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rejectTransfer(ctx *context.Context) {
|
func rejectTransfer(ctx *context.Context) {
|
||||||
@@ -25,7 +25,7 @@ func rejectTransfer(ctx *context.Context) {
|
|||||||
ctx.JSONRedirect(ctx.Repo.Repository.Link())
|
ctx.JSONRedirect(ctx.Repo.Repository.Link())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
handleActionError(ctx, err)
|
handleRepoActionError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ActionTransfer(ctx *context.Context) {
|
func ActionTransfer(ctx *context.Context) {
|
||||||
|
|||||||
+15
-10
@@ -16,14 +16,18 @@ const tplWatch templates.TplName = "repo/header/watch"
|
|||||||
func ActionWatch(ctx *context.Context) {
|
func ActionWatch(ctx *context.Context) {
|
||||||
action := ctx.PathParam("action")
|
action := ctx.PathParam("action")
|
||||||
var err error
|
var err error
|
||||||
if action == "ignore" {
|
switch action {
|
||||||
err = repo_model.WatchIgnoreRepo(ctx, ctx.Doer, ctx.Repo.Repository)
|
case "ignore":
|
||||||
} else {
|
err = repo_model.WatchRepoWithOptions(ctx, ctx.Doer, ctx.Repo.Repository, repo_model.WatchOptions{Mode: repo_model.WatchModeDont})
|
||||||
all := action == "watch" // "participate" is a watch that subscribes to no event on its own
|
case "participate":
|
||||||
err = repo_model.WatchRepoWithOptions(ctx, ctx.Doer, ctx.Repo.Repository, repo_model.WatchOptions{PullRequests: all, Issues: all, Releases: all})
|
err = repo_model.WatchRepoWithOptions(ctx, ctx.Doer, ctx.Repo.Repository, repo_model.WatchOptions{Mode: repo_model.WatchModeNone})
|
||||||
|
case "watch":
|
||||||
|
err = repo_model.WatchRepoWithOptions(ctx, ctx.Doer, ctx.Repo.Repository, repo_model.WatchOptions{Mode: repo_model.WatchModeNormal, WatchPullRequests: true, WatchIssues: true, WatchReleases: true})
|
||||||
|
default:
|
||||||
|
return // impossible
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleActionError(ctx, err)
|
handleRepoActionError(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,12 +49,13 @@ func ActionWatch(ctx *context.Context) {
|
|||||||
// ActionWatchOptions watches the repository with a custom selection of events
|
// ActionWatchOptions watches the repository with a custom selection of events
|
||||||
func ActionWatchOptions(ctx *context.Context) {
|
func ActionWatchOptions(ctx *context.Context) {
|
||||||
opts := repo_model.WatchOptions{ // clearing every event is allowed, it leaves the participating state
|
opts := repo_model.WatchOptions{ // clearing every event is allowed, it leaves the participating state
|
||||||
PullRequests: ctx.FormBool(string(repo_model.WatchPullRequests)),
|
Mode: repo_model.WatchModeNormal,
|
||||||
Issues: ctx.FormBool(string(repo_model.WatchIssues)),
|
WatchPullRequests: ctx.FormBool("pull_requests"),
|
||||||
Releases: ctx.FormBool(string(repo_model.WatchReleases)),
|
WatchIssues: ctx.FormBool("issues"),
|
||||||
|
WatchReleases: ctx.FormBool("releases"),
|
||||||
}
|
}
|
||||||
if err := repo_model.WatchRepoWithOptions(ctx, ctx.Doer, ctx.Repo.Repository, opts); err != nil {
|
if err := repo_model.WatchRepoWithOptions(ctx, ctx.Doer, ctx.Repo.Repository, opts); err != nil {
|
||||||
handleActionError(ctx, err)
|
handleRepoActionError(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSONRedirect("")
|
ctx.JSONRedirect("")
|
||||||
|
|||||||
@@ -74,13 +74,13 @@ func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers
|
|||||||
case activities_model.ActionCommitRepo, activities_model.ActionPushTag, activities_model.ActionDeleteTag, activities_model.ActionDeleteBranch:
|
case activities_model.ActionCommitRepo, activities_model.ActionPushTag, activities_model.ActionDeleteTag, activities_model.ActionDeleteBranch:
|
||||||
allowed = permCode[i] && watcher.IsWatchingAll()
|
allowed = permCode[i] && watcher.IsWatchingAll()
|
||||||
case activities_model.ActionPublishRelease:
|
case activities_model.ActionPublishRelease:
|
||||||
allowed = permCode[i] && watcher.Releases
|
allowed = permCode[i] && watcher.IncludeReleases
|
||||||
case activities_model.ActionCreateIssue, activities_model.ActionCommentIssue, activities_model.ActionCloseIssue, activities_model.ActionReopenIssue:
|
case activities_model.ActionCreateIssue, activities_model.ActionCommentIssue, activities_model.ActionCloseIssue, activities_model.ActionReopenIssue:
|
||||||
allowed = permIssue[i] && watcher.Issues
|
allowed = permIssue[i] && watcher.IncludeIssues
|
||||||
case activities_model.ActionCreatePullRequest, activities_model.ActionCommentPull, activities_model.ActionMergePullRequest, activities_model.ActionClosePullRequest,
|
case activities_model.ActionCreatePullRequest, activities_model.ActionCommentPull, activities_model.ActionMergePullRequest, activities_model.ActionClosePullRequest,
|
||||||
activities_model.ActionReopenPullRequest, activities_model.ActionAutoMergePullRequest, activities_model.ActionApprovePullRequest,
|
activities_model.ActionReopenPullRequest, activities_model.ActionAutoMergePullRequest, activities_model.ActionApprovePullRequest,
|
||||||
activities_model.ActionRejectPullRequest, activities_model.ActionPullReviewDismissed, activities_model.ActionPullRequestReadyForReview:
|
activities_model.ActionRejectPullRequest, activities_model.ActionPullReviewDismissed, activities_model.ActionPullRequestReadyForReview:
|
||||||
allowed = permPR[i] && watcher.PullRequests
|
allowed = permPR[i] && watcher.IncludePullRequests
|
||||||
default:
|
default:
|
||||||
allowed = watcher.IsWatchingAll() // repository events have no watch option of their own
|
allowed = watcher.IsWatchingAll() // repository events have no watch option of their own
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,9 @@ func TestNotifyWatchersRespectsWatchOptions(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
// user 1 watches repo 1 for issues only, user 4 keeps every event
|
// user 1 watches repo 1 for issues only, user 4 keeps every event
|
||||||
assert.NoError(t, repo_model.SetWatchOptions(t.Context(), 1, 1, repo_model.WatchOptions{Issues: true}))
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
assert.NoError(t, repo_model.WatchRepoWithOptions(t.Context(), user1, repo1, repo_model.WatchOptions{Mode: repo_model.WatchModeNormal, WatchIssues: true}))
|
||||||
|
|
||||||
assert.NoError(t, NotifyWatchers(t.Context(),
|
assert.NoError(t, NotifyWatchers(t.Context(),
|
||||||
&activities_model.Action{ActUserID: 8, RepoID: 1, OpType: activities_model.ActionCreateIssue},
|
&activities_model.Action{ActUserID: 8, RepoID: 1, OpType: activities_model.ActionCreateIssue},
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ func TestMailNewReleaseFiltersUnauthorizedWatchers(t *testing.T) {
|
|||||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
unauthorized := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
unauthorized := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||||
|
|
||||||
assert.NoError(t, repo_model.WatchRepo(t.Context(), admin, repo, true))
|
assert.NoError(t, repo_model.WatchRepoAuto(t.Context(), admin, repo, true))
|
||||||
assert.NoError(t, repo_model.WatchRepo(t.Context(), unauthorized, repo, true))
|
assert.NoError(t, repo_model.WatchRepoAuto(t.Context(), unauthorized, repo, true))
|
||||||
|
|
||||||
rel := unittest.AssertExistsAndLoadBean(t, &repo_model.Release{ID: 11})
|
rel := unittest.AssertExistsAndLoadBean(t, &repo_model.Release{ID: 11})
|
||||||
rel.Repo = nil
|
rel.Repo = nil
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func TestOrg(t *testing.T) {
|
|||||||
|
|
||||||
// an outside user watches and stars the repo while the org is still visible
|
// an outside user watches and stars the repo while the org is still visible
|
||||||
watcher := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
watcher := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||||
require.NoError(t, repo_model.WatchRepo(t.Context(), watcher, repo, true))
|
require.NoError(t, repo_model.WatchRepoAuto(t.Context(), watcher, repo, true))
|
||||||
require.NoError(t, repo_model.StarRepo(t.Context(), watcher, repo, true))
|
require.NoError(t, repo_model.StarRepo(t.Context(), watcher, repo, true))
|
||||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID})
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID})
|
||||||
|
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ func AddTeamMember(ctx context.Context, team *organization.Team, user *user_mode
|
|||||||
|
|
||||||
go func(repos []*repo_model.Repository) {
|
go func(repos []*repo_model.Repository) {
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
if err = repo_model.WatchRepo(graceful.GetManager().ShutdownContext(), user, repo, true); err != nil {
|
if err = repo_model.WatchRepoAuto(graceful.GetManager().ShutdownContext(), user, repo, true); err != nil {
|
||||||
log.Error("watch repo failed: %v", err)
|
log.Error("watch repo failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func TestRemoveTeamMemberRemovesSubscriptionsAndStopwatches(t *testing.T) {
|
|||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
|
||||||
|
|
||||||
assert.NoError(t, repo_model.WatchRepo(ctx, user, repo, true))
|
assert.NoError(t, repo_model.WatchRepoAuto(ctx, user, repo, true))
|
||||||
assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(ctx, user.ID, issue.ID, true))
|
assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(ctx, user.ID, issue.ID, true))
|
||||||
ok, err := issues_model.CreateIssueStopwatch(ctx, user, issue)
|
ok, err := issues_model.CreateIssueStopwatch(ctx, user, issue)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -82,7 +82,7 @@ func TestRemoveTeamMemberRemovesSubscriptionsAndStopwatches(t *testing.T) {
|
|||||||
|
|
||||||
watch, err := repo_model.GetWatch(ctx, user.ID, repo.ID)
|
watch, err := repo_model.GetWatch(ctx, user.ID, repo.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, repo_model.IsWatchMode(watch.Mode))
|
assert.False(t, repo_model.IsWatchModeWatching(watch.Mode))
|
||||||
|
|
||||||
_, exists, err := issues_model.GetIssueWatch(ctx, user.ID, issue.ID)
|
_, exists, err := issues_model.GetIssueWatch(ctx, user.ID, issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func RemoveOrgUser(ctx context.Context, org *organization.Organization, user *us
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = repo_model.WatchRepo(ctx, user, repo, false); err != nil {
|
if err = repo_model.WatchRepoAuto(ctx, user, repo, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func DeleteCollaboration(ctx context.Context, repo *repo_model.Repository, colla
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repo_model.WatchRepo(ctx, collaborator, repo, false); err != nil {
|
if err = repo_model.WatchRepoAuto(ctx, collaborator, repo, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ func ReconsiderWatches(ctx context.Context, repo *repo_model.Repository, user *u
|
|||||||
if has, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo); err != nil || has {
|
if has, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo); err != nil || has {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := repo_model.WatchRepo(ctx, user, repo, false); err != nil {
|
if err := repo_model.WatchRepoAuto(ctx, user, repo, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func TestRepository_DeleteCollaborationRemovesSubscriptionsAndStopwatches(t *tes
|
|||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
||||||
assert.NoError(t, repo.LoadOwner(ctx))
|
assert.NoError(t, repo.LoadOwner(ctx))
|
||||||
assert.NoError(t, repo_model.WatchRepo(ctx, user, repo, true))
|
assert.NoError(t, repo_model.WatchRepoAuto(ctx, user, repo, true))
|
||||||
|
|
||||||
hasAccess, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo)
|
hasAccess, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -88,7 +88,7 @@ func TestRepository_DeleteCollaborationRemovesSubscriptionsAndStopwatches(t *tes
|
|||||||
|
|
||||||
watch, err := repo_model.GetWatch(ctx, user.ID, repo.ID)
|
watch, err := repo_model.GetWatch(ctx, user.ID, repo.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, repo_model.IsWatchMode(watch.Mode))
|
assert.False(t, repo_model.IsWatchModeWatching(watch.Mode))
|
||||||
|
|
||||||
_, exists, err := issues_model.GetIssueWatch(ctx, user.ID, tempIssue.ID)
|
_, exists, err := issues_model.GetIssueWatch(ctx, user.ID, tempIssue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ func createRepositoryInDB(ctx context.Context, doer, u *user_model.User, repo *r
|
|||||||
}
|
}
|
||||||
|
|
||||||
if setting.Service.AutoWatchNewRepos {
|
if setting.Service.AutoWatchNewRepos {
|
||||||
if err = repo_model.WatchRepo(ctx, doer, repo, true); err != nil {
|
if err = repo_model.WatchRepoAuto(ctx, doer, repo, true); err != nil {
|
||||||
return fmt.Errorf("WatchRepo: %w", err)
|
return fmt.Errorf("WatchRepo: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func addRepositoryToTeam(ctx context.Context, t *organization.Team, repo *repo_m
|
|||||||
return fmt.Errorf("getMembers: %w", err)
|
return fmt.Errorf("getMembers: %w", err)
|
||||||
}
|
}
|
||||||
for _, u := range t.Members {
|
for _, u := range t.Members {
|
||||||
if err = repo_model.WatchRepo(ctx, u, repo, true); err != nil {
|
if err = repo_model.WatchRepoAuto(ctx, u, repo, true); err != nil {
|
||||||
return fmt.Errorf("watchRepo: %w", err)
|
return fmt.Errorf("watchRepo: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ func removeAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (e
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repo_model.WatchRepo(ctx, user, repo, false); err != nil {
|
if err = repo_model.WatchRepoAuto(ctx, user, repo, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ func removeRepositoryFromTeam(ctx context.Context, t *organization.Team, repo *r
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repo_model.WatchRepo(ctx, member, repo, false); err != nil {
|
if err = repo_model.WatchRepoAuto(ctx, member, repo, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -267,13 +267,13 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
|
|||||||
return fmt.Errorf("decrease old owner repository count: %w", err)
|
return fmt.Errorf("decrease old owner repository count: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := repo_model.WatchRepo(ctx, doer, repo, true); err != nil {
|
if err := repo_model.WatchRepoAuto(ctx, doer, repo, true); err != nil {
|
||||||
return fmt.Errorf("watchRepo: %w", err)
|
return fmt.Errorf("watchRepo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldOwner.IsOrganization() {
|
if oldOwner.IsOrganization() {
|
||||||
// Remove watch for organization.
|
// Remove watch for organization.
|
||||||
if err := repo_model.WatchRepo(ctx, oldOwner, repo, false); err != nil {
|
if err := repo_model.WatchRepoAuto(ctx, oldOwner, repo, false); err != nil {
|
||||||
return fmt.Errorf("watchRepo [false]: %w", err)
|
return fmt.Errorf("watchRepo [false]: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func unwatchRepos(ctx context.Context, watcher, repoOwner *user_model.User) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
if err := repo_model.WatchRepo(ctx, watcher, repo, false); err != nil {
|
if err := repo_model.WatchRepoAuto(ctx, watcher, repo, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@
|
|||||||
<a class="item {{if $isCustom}}active{{end}} show-modal" role="menuitem" aria-label="{{$textCustom}}"
|
<a class="item {{if $isCustom}}active{{end}} show-modal" role="menuitem" aria-label="{{$textCustom}}"
|
||||||
data-modal="#repo-watch-options-modal"
|
data-modal="#repo-watch-options-modal"
|
||||||
data-modal-form.url="{{$.RepoLink}}/action/watch/options"
|
data-modal-form.url="{{$.RepoLink}}/action/watch/options"
|
||||||
data-modal-issues="{{$.RepoWatch.Issues}}"
|
data-modal-issues="{{$.RepoWatch.IncludeIssues}}"
|
||||||
data-modal-pull_requests="{{$.RepoWatch.PullRequests}}"
|
data-modal-pull_requests="{{$.RepoWatch.IncludePullRequests}}"
|
||||||
data-modal-releases="{{$.RepoWatch.Releases}}"
|
data-modal-releases="{{$.RepoWatch.IncludeReleases}}"
|
||||||
>
|
>
|
||||||
{{svg "octicon-check" 16 (Iif $isCustom "" "tw-invisible")}}
|
{{svg "octicon-check" 16 (Iif $isCustom "" "tw-invisible")}}
|
||||||
<div>{{$textCustom}}<div class="tw-text-12 tw-text-text-light-2">{{ctx.Locale.Tr "repo.watch.mode.custom.desc"}}</div></div>
|
<div>{{$textCustom}}<div class="tw-text-12 tw-text-text-light-2">{{ctx.Locale.Tr "repo.watch.mode.custom.desc"}}</div></div>
|
||||||
|
|||||||
@@ -60,9 +60,9 @@
|
|||||||
<button class="btn flex-text-inline show-modal"
|
<button class="btn flex-text-inline show-modal"
|
||||||
data-modal="#repo-watch-options-modal"
|
data-modal="#repo-watch-options-modal"
|
||||||
data-modal-form.url="{{.Link}}/action/watch/options"
|
data-modal-form.url="{{.Link}}/action/watch/options"
|
||||||
data-modal-issues="{{$watch.Issues}}"
|
data-modal-issues="{{$watch.IncludeIssues}}"
|
||||||
data-modal-pull_requests="{{$watch.PullRequests}}"
|
data-modal-pull_requests="{{$watch.IncludePullRequests}}"
|
||||||
data-modal-releases="{{$watch.Releases}}"
|
data-modal-releases="{{$watch.IncludeReleases}}"
|
||||||
data-tooltip-content="{{ctx.Locale.Tr "notifications"}}"
|
data-tooltip-content="{{ctx.Locale.Tr "notifications"}}"
|
||||||
>{{svg "octicon-gear" 16}}</button>
|
>{{svg "octicon-gear" 16}}</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user