@@ -10,8 +10,6 @@ import (
10
10
"code.gitea.io/gitea/models"
11
11
"code.gitea.io/gitea/modules/log"
12
12
"code.gitea.io/gitea/modules/references"
13
-
14
- "github.com/unknwon/com"
15
13
)
16
14
17
15
func fallbackMailSubject (issue * models.Issue ) string {
@@ -24,64 +22,70 @@ func fallbackMailSubject(issue *models.Issue) string {
24
22
// 2. Users who are not in 1. but get mentioned in current issue/comment.
25
23
func mailIssueCommentToParticipants (issue * models.Issue , doer * models.User , actionType models.ActionType , content string , comment * models.Comment , mentions []string ) error {
26
24
27
- watchers , err := models .GetWatchers (issue .RepoID )
25
+ // =========== Repo watchers ===========
26
+ // *Watch
27
+ rwatchers , err := models .GetWatchers (issue .RepoID )
28
28
if err != nil {
29
- return fmt .Errorf ("getWatchers [repo_id: %d] : %v" , issue .RepoID , err )
29
+ return fmt .Errorf ("GetWatchers(%d) : %v" , issue .RepoID , err )
30
30
}
31
- participants , err := models .GetParticipantsByIssueID (issue .ID )
31
+ watcherids := make ([]int64 , len (rwatchers ))
32
+ for i := range rwatchers {
33
+ watcherids [i ] = rwatchers [i ].UserID
34
+ }
35
+ watchers , err := models .GetUsersByIDs (watcherids )
32
36
if err != nil {
33
- return fmt .Errorf ("getParticipantsByIssueID [issue_id: %d] : %v" , issue .ID , err )
37
+ return fmt .Errorf ("GetUsersByIDs(%d) : %v" , issue .RepoID , err )
34
38
}
35
39
36
- // In case the issue poster is not watching the repository and is active,
37
- // even if we have duplicated in watchers, can be safely filtered out.
38
- err = issue .LoadPoster ()
40
+ // =========== Issue watchers ===========
41
+ // IssueWatchList
42
+ iwl , err := models .GetIssueWatchers (issue .ID )
43
+ if err != nil {
44
+ return fmt .Errorf ("GetIssueWatchers(%d): %v" , issue .ID , err )
45
+ }
46
+ // UserList ([]*User)
47
+ iwatchers , err := iwl .LoadWatchUsers ()
39
48
if err != nil {
40
- return fmt .Errorf ("GetUserByID [%d] : %v" , issue .PosterID , err )
49
+ return fmt .Errorf ("GetIssueWatchers(%d) : %v" , issue .ID , err )
41
50
}
42
- if issue .PosterID != doer .ID && issue .Poster .IsActive && ! issue .Poster .ProhibitLogin {
43
- participants = append (participants , issue .Poster )
51
+
52
+ // =========== Participants (i.e. commenters, reviewers) ===========
53
+ // []*User
54
+ participants , err := models .GetParticipantsByIssueID (issue .ID )
55
+ if err != nil {
56
+ return fmt .Errorf ("GetParticipantsByIssueID(%d): %v" , issue .ID , err )
44
57
}
45
58
46
- // Assignees must receive any communications
59
+ // =========== Assignees ===========
60
+ // []*User
47
61
assignees , err := models .GetAssigneesByIssue (issue )
48
62
if err != nil {
49
63
return err
50
64
}
51
65
52
- for _ , assignee := range assignees {
53
- if assignee .ID != doer .ID {
54
- participants = append (participants , assignee )
55
- }
66
+ // =========== Original poster ===========
67
+ // *User
68
+ err = issue .LoadPoster ()
69
+ if err != nil {
70
+ return fmt .Errorf ("LoadPoster(%d): %v" , issue .PosterID , err )
56
71
}
57
72
58
- tos := make ([]string , 0 , len (watchers )) // List of email addresses.
59
- names := make ([]string , 0 , len (watchers ))
60
- for i := range watchers {
61
- if watchers [i ].UserID == doer .ID {
62
- continue
63
- }
73
+ recipients := make ([]* models.User , 0 , 10 )
74
+ visited := make (map [string ]bool , 10 )
64
75
65
- to , err := models .GetUserByID (watchers [i ].UserID )
66
- if err != nil {
67
- return fmt .Errorf ("GetUserByID [%d]: %v" , watchers [i ].UserID , err )
68
- }
69
- if to .IsOrganization () || to .EmailNotifications () != models .EmailNotificationsEnabled {
70
- continue
71
- }
76
+ // Avoid mailing the doer
77
+ visited [doer .LowerName ] = true
72
78
73
- tos = append (tos , to .Email )
74
- names = append (names , to .Name )
75
- }
76
- for i := range participants {
77
- if participants [i ].ID == doer .ID ||
78
- com .IsSliceContainsStr (names , participants [i ].Name ) ||
79
- participants [i ].EmailNotifications () != models .EmailNotificationsEnabled {
80
- continue
81
- }
79
+ // Normalize all aditions to make all the relevant checks
80
+ recipients = addUniqueUsers (visited , recipients , []* models.User {issue .Poster })
81
+ recipients = addUniqueUsers (visited , recipients , watchers )
82
+ recipients = addUniqueUsers (visited , recipients , iwatchers )
83
+ recipients = addUniqueUsers (visited , recipients , participants )
84
+ recipients = addUniqueUsers (visited , recipients , assignees )
82
85
83
- tos = append (tos , participants [i ].Email )
84
- names = append (names , participants [i ].Name )
86
+ tos := make ([]string , 0 , len (recipients )) // List of email addresses.
87
+ for _ , to := range recipients {
88
+ tos = append (tos , to .Email )
85
89
}
86
90
87
91
if err := issue .LoadRepo (); err != nil {
@@ -92,15 +96,13 @@ func mailIssueCommentToParticipants(issue *models.Issue, doer *models.User, acti
92
96
SendIssueCommentMail (issue , doer , actionType , content , comment , []string {to })
93
97
}
94
98
95
- // Mail mentioned people and exclude watchers.
96
- names = append ( names , doer . Name )
97
- tos = make ([] string , 0 , len ( mentions )) // list of user names.
98
- for i := range mentions {
99
- if com . IsSliceContainsStr ( names , mentions [ i ]) {
100
- continue
99
+ // Mail mentioned people and exclude previous recipients
100
+ tos = make ([] string , 0 , len ( mentions )) // mentions come as a list of user names
101
+ for _ , mention := range mentions {
102
+ if _ , ok := visited [ mention ]; ! ok {
103
+ visited [ mention ] = true
104
+ tos = append ( tos , mention )
101
105
}
102
-
103
- tos = append (tos , mentions [i ])
104
106
}
105
107
106
108
emails := models .GetUserEmailsByNames (tos )
@@ -112,6 +114,20 @@ func mailIssueCommentToParticipants(issue *models.Issue, doer *models.User, acti
112
114
return nil
113
115
}
114
116
117
+ func addUniqueUsers (visited map [string ]bool , current []* models.User , list []* models.User ) []* models.User {
118
+ for _ , u := range list {
119
+ if _ , ok := visited [u .LowerName ]; ! ok &&
120
+ ! u .IsOrganization () &&
121
+ u .EmailNotifications () == models .EmailNotificationsEnabled &&
122
+ ! u .ProhibitLogin &&
123
+ u .IsActive {
124
+ visited [u .LowerName ] = true
125
+ current = append (current , u )
126
+ }
127
+ }
128
+ return current
129
+ }
130
+
115
131
// MailParticipants sends new issue thread created emails to repository watchers
116
132
// and mentioned people.
117
133
func MailParticipants (issue * models.Issue , doer * models.User , opType models.ActionType ) error {
0 commit comments