* Add support for AUTO_WATCH_ON_CHANGES and AUTO_WATCH_ON_CLONE * Update models/repo_watch.go Co-Authored-By: Lauris BH <lauris@nix.lv> * Round up changes suggested by lafriks * Added changes suggested from automated tests * Updated deleteUser to take RepoWatchModeDont into account, corrected inverted DefaultWatchOnClone and DefaultWatchOnChanges behaviour, updated and added tests. * Reinsert import "github.com/Unknwon/com" on http.go * Add migration for new column `watch`.`mode` * Remove serv code * Remove WATCH_ON_CLONE; use hooks, add integrations * Renamed watch_test.go to repo_watch_test.go * Correct fmt * Add missing EOL * Correct name of test function * Reword cheat and ini descriptions * Add update to migration to ensure column value * Clarify comment Co-Authored-By: zeripath <art27@cantab.net> * Simplify if conditiontags/v1.11.0-rc1
; When adding a repo to a team or creating a new repo all team members will watch the | ; When adding a repo to a team or creating a new repo all team members will watch the | ||||
; repo automatically if enabled | ; repo automatically if enabled | ||||
AUTO_WATCH_NEW_REPOS = true | AUTO_WATCH_NEW_REPOS = true | ||||
; Default value for AutoWatchOnChanges | |||||
; Make the user watch a repository When they commit for the first time | |||||
AUTO_WATCH_ON_CHANGES = false | |||||
[webhook] | [webhook] | ||||
; Hook task queue length, increase if webhook shooting starts hanging | ; Hook task queue length, increase if webhook shooting starts hanging |
on this instance. | on this instance. | ||||
- `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button | - `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button | ||||
- `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created | - `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created | ||||
- `AUTO_WATCH_ON_CHANGES`: **false**: Enable this to make users watch a repository after their first commit to it | |||||
- `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private". | - `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private". | ||||
- `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation. | - `DEFAULT_ORG_MEMBER_VISIBLE`: **false** True will make the membership of the users visible when added to the organisation. | ||||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package integrations | |||||
import ( | |||||
"net/url" | |||||
"testing" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
) | |||||
func TestRepoWatch(t *testing.T) { | |||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { | |||||
// Test round-trip auto-watch | |||||
setting.Service.AutoWatchOnChanges = true | |||||
session := loginUser(t, "user2") | |||||
models.AssertNotExistsBean(t, &models.Watch{UserID: 2, RepoID: 3}) | |||||
testEditFile(t, session, "user3", "repo3", "master", "README.md", "Hello, World (Edited for watch)\n") | |||||
models.AssertExistsAndLoadBean(t, &models.Watch{UserID: 2, RepoID: 3, Mode: models.RepoWatchModeAuto}) | |||||
}) | |||||
} |
func (repo *Repository) checkForConsistency(t *testing.T) { | func (repo *Repository) checkForConsistency(t *testing.T) { | ||||
assert.Equal(t, repo.LowerName, strings.ToLower(repo.Name), "repo: %+v", repo) | assert.Equal(t, repo.LowerName, strings.ToLower(repo.Name), "repo: %+v", repo) | ||||
assertCount(t, &Star{RepoID: repo.ID}, repo.NumStars) | assertCount(t, &Star{RepoID: repo.ID}, repo.NumStars) | ||||
assertCount(t, &Watch{RepoID: repo.ID}, repo.NumWatches) | |||||
assertCount(t, &Milestone{RepoID: repo.ID}, repo.NumMilestones) | assertCount(t, &Milestone{RepoID: repo.ID}, repo.NumMilestones) | ||||
assertCount(t, &Repository{ForkID: repo.ID}, repo.NumForks) | assertCount(t, &Repository{ForkID: repo.ID}, repo.NumForks) | ||||
if repo.IsFork { | if repo.IsFork { | ||||
AssertExistsAndLoadBean(t, &Repository{ID: repo.ForkID}) | AssertExistsAndLoadBean(t, &Repository{ID: repo.ForkID}) | ||||
} | } | ||||
actual := getCount(t, x.Where("is_pull=?", false), &Issue{RepoID: repo.ID}) | |||||
actual := getCount(t, x.Where("Mode<>?", RepoWatchModeDont), &Watch{RepoID: repo.ID}) | |||||
assert.EqualValues(t, repo.NumWatches, actual, | |||||
"Unexpected number of watches for repo %+v", repo) | |||||
actual = getCount(t, x.Where("is_pull=?", false), &Issue{RepoID: repo.ID}) | |||||
assert.EqualValues(t, repo.NumIssues, actual, | assert.EqualValues(t, repo.NumIssues, actual, | ||||
"Unexpected number of issues for repo %+v", repo) | "Unexpected number of issues for repo %+v", repo) | ||||
num_closed_pulls: 0 | num_closed_pulls: 0 | ||||
num_milestones: 3 | num_milestones: 3 | ||||
num_closed_milestones: 1 | num_closed_milestones: 1 | ||||
num_watches: 3 | |||||
num_watches: 4 | |||||
status: 0 | status: 0 | ||||
- | - |
id: 1 | id: 1 | ||||
user_id: 1 | user_id: 1 | ||||
repo_id: 1 | repo_id: 1 | ||||
mode: 1 # normal | |||||
- | - | ||||
id: 2 | id: 2 | ||||
user_id: 4 | user_id: 4 | ||||
repo_id: 1 | repo_id: 1 | ||||
mode: 1 # normal | |||||
- | - | ||||
id: 3 | id: 3 | ||||
user_id: 9 | user_id: 9 | ||||
repo_id: 1 | repo_id: 1 | ||||
mode: 1 # normal | |||||
- | |||||
id: 4 | |||||
user_id: 8 | |||||
repo_id: 1 | |||||
mode: 2 # don't watch | |||||
- | |||||
id: 5 | |||||
user_id: 11 | |||||
repo_id: 1 | |||||
mode: 3 # auto |
NewMigration("remove unnecessary columns from label", removeLabelUneededCols), | NewMigration("remove unnecessary columns from label", removeLabelUneededCols), | ||||
// v105 -> v106 | // v105 -> v106 | ||||
NewMigration("add includes_all_repositories to teams", addTeamIncludesAllRepositories), | NewMigration("add includes_all_repositories to teams", addTeamIncludesAllRepositories), | ||||
// v106 -> v107 | |||||
NewMigration("add column `mode` to table watch", addModeColumnToWatch), | |||||
} | } | ||||
// Migrate database to current version | // Migrate database to current version |
// Copyright 2019 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package migrations | |||||
import ( | |||||
"xorm.io/xorm" | |||||
) | |||||
// RepoWatchMode specifies what kind of watch the user has on a repository | |||||
type RepoWatchMode int8 | |||||
// Watch is connection request for receiving repository notification. | |||||
type Watch struct { | |||||
ID int64 `xorm:"pk autoincr"` | |||||
Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` | |||||
} | |||||
func addModeColumnToWatch(x *xorm.Engine) (err error) { | |||||
if err = x.Sync2(new(Watch)); err != nil { | |||||
return | |||||
} | |||||
_, err = x.Exec("UPDATE `watch` SET `mode` = 1") | |||||
return err | |||||
} |
checkers := []*repoChecker{ | checkers := []*repoChecker{ | ||||
// Repository.NumWatches | // Repository.NumWatches | ||||
{ | { | ||||
"SELECT repo.id FROM `repository` repo WHERE repo.num_watches!=(SELECT COUNT(*) FROM `watch` WHERE repo_id=repo.id)", | |||||
"UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=?) WHERE id=?", | |||||
"SELECT repo.id FROM `repository` repo WHERE repo.num_watches!=(SELECT COUNT(*) FROM `watch` WHERE repo_id=repo.id AND mode<>2)", | |||||
"UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", | |||||
"repository count 'num_watches'", | "repository count 'num_watches'", | ||||
}, | }, | ||||
// Repository.NumStars | // Repository.NumStars |
package models | package models | ||||
import "fmt" | |||||
import ( | |||||
"fmt" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
) | |||||
// RepoWatchMode specifies what kind of watch the user has on a repository | |||||
type RepoWatchMode int8 | |||||
const ( | |||||
// RepoWatchModeNone don't watch | |||||
RepoWatchModeNone RepoWatchMode = iota // 0 | |||||
// RepoWatchModeNormal watch repository (from other sources) | |||||
RepoWatchModeNormal // 1 | |||||
// RepoWatchModeDont explicit don't auto-watch | |||||
RepoWatchModeDont // 2 | |||||
// RepoWatchModeAuto watch repository (from AutoWatchOnChanges) | |||||
RepoWatchModeAuto // 3 | |||||
) | |||||
// 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"` | |||||
UserID int64 `xorm:"UNIQUE(watch)"` | |||||
RepoID int64 `xorm:"UNIQUE(watch)"` | |||||
ID int64 `xorm:"pk autoincr"` | |||||
UserID int64 `xorm:"UNIQUE(watch)"` | |||||
RepoID int64 `xorm:"UNIQUE(watch)"` | |||||
Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` | |||||
} | } | ||||
func isWatching(e Engine, userID, repoID int64) bool { | |||||
has, _ := e.Get(&Watch{UserID: userID, RepoID: repoID}) | |||||
return has | |||||
// getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found | |||||
func getWatch(e Engine, userID, repoID int64) (Watch, error) { | |||||
watch := Watch{UserID: userID, RepoID: repoID} | |||||
has, err := e.Get(&watch) | |||||
if err != nil { | |||||
return watch, err | |||||
} | |||||
if !has { | |||||
watch.Mode = RepoWatchModeNone | |||||
} | |||||
return watch, nil | |||||
} | |||||
// Decodes watchability of RepoWatchMode | |||||
func isWatchMode(mode RepoWatchMode) bool { | |||||
return mode != RepoWatchModeNone && mode != RepoWatchModeDont | |||||
} | } | ||||
// IsWatching checks if user has watched given repository. | // IsWatching checks if user has watched given repository. | ||||
func IsWatching(userID, repoID int64) bool { | func IsWatching(userID, repoID int64) bool { | ||||
return isWatching(x, userID, repoID) | |||||
watch, err := getWatch(x, userID, repoID) | |||||
return err == nil && isWatchMode(watch.Mode) | |||||
} | } | ||||
func watchRepo(e Engine, userID, repoID int64, watch bool) (err error) { | |||||
if watch { | |||||
if isWatching(e, userID, repoID) { | |||||
return nil | |||||
} | |||||
if _, err = e.Insert(&Watch{RepoID: repoID, UserID: userID}); err != nil { | |||||
func watchRepoMode(e Engine, watch Watch, mode RepoWatchMode) (err error) { | |||||
if watch.Mode == mode { | |||||
return nil | |||||
} | |||||
if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) { | |||||
// Don't auto watch if already watching or deliberately not watching | |||||
return nil | |||||
} | |||||
hadrec := watch.Mode != RepoWatchModeNone | |||||
needsrec := mode != RepoWatchModeNone | |||||
repodiff := 0 | |||||
if isWatchMode(mode) && !isWatchMode(watch.Mode) { | |||||
repodiff = 1 | |||||
} else if !isWatchMode(mode) && isWatchMode(watch.Mode) { | |||||
repodiff = -1 | |||||
} | |||||
watch.Mode = mode | |||||
if !hadrec && needsrec { | |||||
watch.Mode = mode | |||||
if _, err = e.Insert(watch); err != nil { | |||||
return err | return err | ||||
} | } | ||||
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?", repoID) | |||||
} else { | |||||
if !isWatching(e, userID, repoID) { | |||||
return nil | |||||
} | |||||
if _, err = e.Delete(&Watch{0, userID, repoID}); err != nil { | |||||
} else if needsrec { | |||||
watch.Mode = mode | |||||
if _, err := e.ID(watch.ID).AllCols().Update(watch); err != nil { | |||||
return err | return err | ||||
} | } | ||||
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?", repoID) | |||||
} else if _, err = e.Delete(Watch{ID: watch.ID}); err != nil { | |||||
return err | |||||
} | |||||
if repodiff != 0 { | |||||
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repodiff, watch.RepoID) | |||||
} | |||||
return err | |||||
} | |||||
// WatchRepoMode watch repository in specific mode. | |||||
func WatchRepoMode(userID, repoID int64, mode RepoWatchMode) (err error) { | |||||
var watch Watch | |||||
if watch, err = getWatch(x, userID, repoID); err != nil { | |||||
return err | |||||
} | |||||
return watchRepoMode(x, watch, mode) | |||||
} | |||||
func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { | |||||
var watch Watch | |||||
if watch, err = getWatch(e, userID, repoID); err != nil { | |||||
return err | |||||
} | |||||
if !doWatch && watch.Mode == RepoWatchModeAuto { | |||||
err = watchRepoMode(e, watch, RepoWatchModeDont) | |||||
} else if !doWatch { | |||||
err = watchRepoMode(e, watch, RepoWatchModeNone) | |||||
} else { | |||||
err = watchRepoMode(e, watch, RepoWatchModeNormal) | |||||
} | } | ||||
return err | return err | ||||
} | } | ||||
func getWatchers(e Engine, repoID int64) ([]*Watch, error) { | func getWatchers(e Engine, repoID int64) ([]*Watch, error) { | ||||
watches := make([]*Watch, 0, 10) | watches := make([]*Watch, 0, 10) | ||||
return watches, e.Where("`watch`.repo_id=?", repoID). | return watches, e.Where("`watch`.repo_id=?", repoID). | ||||
And("`watch`.mode<>?", RepoWatchModeDont). | |||||
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"). | ||||
func (repo *Repository) GetWatchers(page int) ([]*User, error) { | func (repo *Repository) GetWatchers(page int) ([]*User, error) { | ||||
users := make([]*User, 0, ItemsPerPage) | users := make([]*User, 0, ItemsPerPage) | ||||
sess := x.Where("watch.repo_id=?", repo.ID). | sess := x.Where("watch.repo_id=?", repo.ID). | ||||
Join("LEFT", "watch", "`user`.id=`watch`.user_id") | |||||
Join("LEFT", "watch", "`user`.id=`watch`.user_id"). | |||||
And("`watch`.mode<>?", RepoWatchModeDont) | |||||
if page > 0 { | if page > 0 { | ||||
sess = sess.Limit(ItemsPerPage, (page-1)*ItemsPerPage) | sess = sess.Limit(ItemsPerPage, (page-1)*ItemsPerPage) | ||||
} | } | ||||
func NotifyWatchers(act *Action) error { | func NotifyWatchers(act *Action) error { | ||||
return notifyWatchers(x, act) | return notifyWatchers(x, act) | ||||
} | } | ||||
func watchIfAuto(e Engine, userID, repoID int64, isWrite bool) error { | |||||
if !isWrite || !setting.Service.AutoWatchOnChanges { | |||||
return nil | |||||
} | |||||
watch, err := getWatch(e, userID, repoID) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
if watch.Mode != RepoWatchModeNone { | |||||
return nil | |||||
} | |||||
return watchRepoMode(e, watch, RepoWatchModeAuto) | |||||
} | |||||
// WatchIfAuto subscribes to repo if AutoWatchOnChanges is set | |||||
func WatchIfAuto(userID int64, repoID int64, isWrite bool) error { | |||||
return watchIfAuto(x, userID, repoID, isWrite) | |||||
} |
import ( | import ( | ||||
"testing" | "testing" | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"github.com/stretchr/testify/assert" | "github.com/stretchr/testify/assert" | ||||
) | ) | ||||
assert.True(t, IsWatching(1, 1)) | assert.True(t, IsWatching(1, 1)) | ||||
assert.True(t, IsWatching(4, 1)) | assert.True(t, IsWatching(4, 1)) | ||||
assert.True(t, IsWatching(11, 1)) | |||||
assert.False(t, IsWatching(1, 5)) | assert.False(t, IsWatching(1, 5)) | ||||
assert.False(t, IsWatching(8, 1)) | |||||
assert.False(t, IsWatching(NonexistentID, NonexistentID)) | assert.False(t, IsWatching(NonexistentID, NonexistentID)) | ||||
} | } | ||||
} | } | ||||
assert.NoError(t, NotifyWatchers(action)) | assert.NoError(t, NotifyWatchers(action)) | ||||
// One watchers are inactive, thus action is only created for user 8, 1, 4 | |||||
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11 | |||||
AssertExistsAndLoadBean(t, &Action{ | AssertExistsAndLoadBean(t, &Action{ | ||||
ActUserID: action.ActUserID, | ActUserID: action.ActUserID, | ||||
UserID: 8, | UserID: 8, | ||||
RepoID: action.RepoID, | RepoID: action.RepoID, | ||||
OpType: action.OpType, | OpType: action.OpType, | ||||
}) | }) | ||||
AssertExistsAndLoadBean(t, &Action{ | |||||
ActUserID: action.ActUserID, | |||||
UserID: 11, | |||||
RepoID: action.RepoID, | |||||
OpType: action.OpType, | |||||
}) | |||||
} | |||||
func TestWatchIfAuto(t *testing.T) { | |||||
assert.NoError(t, PrepareTestDatabase()) | |||||
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) | |||||
watchers, err := repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, repo.NumWatches) | |||||
setting.Service.AutoWatchOnChanges = false | |||||
prevCount := repo.NumWatches | |||||
// Must not add watch | |||||
assert.NoError(t, WatchIfAuto(8, 1, true)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount) | |||||
// Should not add watch | |||||
assert.NoError(t, WatchIfAuto(10, 1, true)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount) | |||||
setting.Service.AutoWatchOnChanges = true | |||||
// Must not add watch | |||||
assert.NoError(t, WatchIfAuto(8, 1, true)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount) | |||||
// Should not add watch | |||||
assert.NoError(t, WatchIfAuto(12, 1, false)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount) | |||||
// Should add watch | |||||
assert.NoError(t, WatchIfAuto(12, 1, true)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount+1) | |||||
// Should remove watch, inhibit from adding auto | |||||
assert.NoError(t, WatchRepo(12, 1, false)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount) | |||||
// Must not add watch | |||||
assert.NoError(t, WatchIfAuto(12, 1, true)) | |||||
watchers, err = repo.GetWatchers(1) | |||||
assert.NoError(t, err) | |||||
assert.Len(t, watchers, prevCount) | |||||
} | |||||
func TestWatchRepoMode(t *testing.T) { | |||||
assert.NoError(t, PrepareTestDatabase()) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0) | |||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeAuto)) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: RepoWatchModeAuto}, 1) | |||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeNormal)) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: RepoWatchModeNormal}, 1) | |||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeDont)) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: RepoWatchModeDont}, 1) | |||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeNone)) | |||||
AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0) | |||||
} | } |
// ***** START: Watch ***** | // ***** START: Watch ***** | ||||
watchedRepoIDs := make([]int64, 0, 10) | watchedRepoIDs := make([]int64, 0, 10) | ||||
if err = e.Table("watch").Cols("watch.repo_id"). | if err = e.Table("watch").Cols("watch.repo_id"). | ||||
Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil { | |||||
Where("watch.user_id = ?", u.ID).And("watch.mode <>?", RepoWatchModeDont).Find(&watchedRepoIDs); err != nil { | |||||
return fmt.Errorf("get all watches: %v", err) | return fmt.Errorf("get all watches: %v", err) | ||||
} | } | ||||
if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(Repository)); err != nil { | if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(Repository)); err != nil { | ||||
// GetWatchedRepos returns the repos watched by a particular user | // GetWatchedRepos returns the repos watched by a particular user | ||||
func GetWatchedRepos(userID int64, private bool) ([]*Repository, error) { | func GetWatchedRepos(userID int64, private bool) ([]*Repository, error) { | ||||
sess := x.Where("watch.user_id=?", userID). | sess := x.Where("watch.user_id=?", userID). | ||||
And("`watch`.mode<>?", RepoWatchModeDont). | |||||
Join("LEFT", "watch", "`repository`.id=`watch`.repo_id") | Join("LEFT", "watch", "`repository`.id=`watch`.repo_id") | ||||
if !private { | if !private { | ||||
sess = sess.And("is_private=?", false) | sess = sess.And("is_private=?", false) |
if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { | if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { | ||||
models.UpdateRepoIndexer(repo) | models.UpdateRepoIndexer(repo) | ||||
} | } | ||||
if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil { | |||||
log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err) | |||||
} | |||||
return nil | return nil | ||||
} | } |
NoReplyAddress string | NoReplyAddress string | ||||
EnableUserHeatmap bool | EnableUserHeatmap bool | ||||
AutoWatchNewRepos bool | AutoWatchNewRepos bool | ||||
AutoWatchOnChanges bool | |||||
DefaultOrgMemberVisible bool | DefaultOrgMemberVisible bool | ||||
// OpenID settings | // OpenID settings | ||||
Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply.example.org") | Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply.example.org") | ||||
Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true) | Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true) | ||||
Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true) | Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true) | ||||
Service.AutoWatchOnChanges = sec.Key("AUTO_WATCH_ON_CHANGES").MustBool(false) | |||||
Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) | Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) | ||||
Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] | Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] | ||||
Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool() | Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool() |