num_pulls: 2
num_closed_pulls: 0
num_milestones: 2
- num_watches: 2
+ num_watches: 3
-
id: 2
id: 2
user_id: 4
repo_id: 1
+
+-
+ id: 3
+ user_id: 10
+ repo_id: 1
func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) {
userIDs := make([]int64, 0, 5)
if err := e.Table("comment").Cols("poster_id").
- Where("issue_id = ?", issueID).
- And("type = ?", CommentTypeComment).
+ Where("`comment`.issue_id = ?", issueID).
+ And("`comment`.type = ?", CommentTypeComment).
+ And("`user`.is_active = ?", true).
+ And("`user`.prohibit_login = ?", false).
+ Join("INNER", "user", "`user`.id = `comment`.poster_id").
Distinct("poster_id").
Find(&userIDs); err != nil {
return nil, fmt.Errorf("get poster IDs: %v", err)
return fmt.Errorf("getParticipantsByIssueID [issue_id: %d]: %v", issue.ID, err)
}
- // In case the issue poster is not watching the repository,
+ // In case the issue poster is not watching the repository and is active,
// even if we have duplicated in watchers, can be safely filtered out.
- if issue.PosterID != doer.ID {
+ poster, err := GetUserByID(issue.PosterID)
+ if err != nil {
+ return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
+ }
+ if issue.PosterID != doer.ID && poster.IsActive && !poster.ProhibitLogin {
participants = append(participants, issue.Poster)
}
// User 1 is issue1 poster (see fixtures/issue.yml)
// User 2 only labeled issue1 (see fixtures/comment.yml)
// Users 3 and 5 made actual comments (see fixtures/comment.yml)
- checkParticipants(1, []int{3, 5})
+ // User 3 is inactive, thus not active participant
+ checkParticipants(1, []int{5})
}
func TestIssue_AddLabel(t *testing.T) {
func getIssueWatchers(e Engine, issueID int64) (watches []*IssueWatch, err error) {
err = e.
- Where("issue_id = ?", issueID).
+ Where("`issue_watch`.issue_id = ?", issueID).
+ And("`user`.is_active = ?", true).
+ And("`user`.prohibit_login = ?", false).
+ Join("INNER", "user", "`user`.id = `issue_watch`.user_id").
Find(&watches)
return
}
iws, err := GetIssueWatchers(1)
assert.NoError(t, err)
+ // Watcher is inactive, thus 0
+ assert.Equal(t, 0, len(iws))
+
+ iws, err = GetIssueWatchers(2)
+ assert.NoError(t, err)
assert.Equal(t, 1, len(iws))
iws, err = GetIssueWatchers(5)
NewMigration("adds time tracking and stopwatches", addTimetracking),
// v40 -> v41
NewMigration("migrate protected branch struct", migrateProtectedBranchStruct),
+ // v41 -> v42
+ NewMigration("add default value to user prohibit_login", addDefaultValueToUserProhibitLogin),
}
// Migrate database to current version
--- /dev/null
+// Copyright 2017 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 (
+ "fmt"
+
+ "code.gitea.io/gitea/models"
+
+ "github.com/go-xorm/xorm"
+)
+
+func addDefaultValueToUserProhibitLogin(x *xorm.Engine) (err error) {
+ user := &models.User{
+ ProhibitLogin: false,
+ }
+
+ if _, err := x.Where("`prohibit_login` IS NULL").Cols("prohibit_login").Update(user); err != nil {
+ return err
+ }
+
+ dialect := x.Dialect().DriverName()
+
+ switch dialect {
+ case "mysql":
+ _, err = x.Exec("ALTER TABLE user MODIFY `prohibit_login` tinyint(1) NOT NULL DEFAULT 0")
+ case "postgres":
+ _, err = x.Exec("ALTER TABLE \"user\" ALTER COLUMN `prohibit_login` SET NOT NULL, ALTER COLUMN `prohibit_login` SET DEFAULT false")
+ case "mssql":
+ // xorm already set DEFAULT 0 for data type BIT in mssql
+ _, err = x.Exec(`ALTER TABLE [user] ALTER COLUMN "prohibit_login" BIT NOT NULL`)
+ case "sqlite3":
+ }
+
+ if err != nil {
+ return fmt.Errorf("Error changing user prohibit_login column definition: %v", err)
+ }
+
+ return err
+}
assert.NoError(t, CreateOrUpdateIssueNotifications(issue, 2))
- notf := AssertExistsAndLoadBean(t, &Notification{UserID: 1, IssueID: issue.ID}).(*Notification)
- assert.Equal(t, NotificationStatusUnread, notf.Status)
- notf = AssertExistsAndLoadBean(t, &Notification{UserID: 4, IssueID: issue.ID}).(*Notification)
+ // Two watchers are inactive, thus only notification for user 10 is created
+ notf := AssertExistsAndLoadBean(t, &Notification{UserID: 10, IssueID: issue.ID}).(*Notification)
assert.Equal(t, NotificationStatusUnread, notf.Status)
CheckConsistencyFor(t, &Issue{ID: issue.ID})
}
func getWatchers(e Engine, repoID int64) ([]*Watch, error) {
watches := make([]*Watch, 0, 10)
- return watches, e.Find(&watches, &Watch{RepoID: repoID})
+ return watches, e.Where("`watch`.repo_id=?", repoID).
+ And("`user`.is_active=?", true).
+ And("`user`.prohibit_login=?", false).
+ Join("INNER", "user", "`user`.id = `watch`.user_id").
+ Find(&watches)
}
// GetWatchers returns all watchers of given repository.
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
watches, err := GetWatchers(repo.ID)
assert.NoError(t, err)
- assert.Len(t, watches, repo.NumWatches)
+ // Two watchers are inactive, thus minus 2
+ assert.Len(t, watches, repo.NumWatches-2)
for _, watch := range watches {
assert.EqualValues(t, repo.ID, watch.RepoID)
}
}
assert.NoError(t, NotifyWatchers(action))
+ // Two watchers are inactive, thus action is only created for user 8, 10
AssertExistsAndLoadBean(t, &Action{
ActUserID: action.ActUserID,
- UserID: 1,
- RepoID: action.RepoID,
- OpType: action.OpType,
- })
- AssertExistsAndLoadBean(t, &Action{
- ActUserID: action.ActUserID,
- UserID: 4,
+ UserID: 8,
RepoID: action.RepoID,
OpType: action.OpType,
})
AssertExistsAndLoadBean(t, &Action{
ActUserID: action.ActUserID,
- UserID: 8,
+ UserID: 10,
RepoID: action.RepoID,
OpType: action.OpType,
})
AllowGitHook bool
AllowImportLocal bool // Allow migrate repository by local path
AllowCreateOrganization bool `xorm:"DEFAULT true"`
- ProhibitLogin bool
+ ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"`
// Avatar
Avatar string `xorm:"VARCHAR(2048) NOT NULL"`