Skip to content

Commit d68421f

Browse files
committed
Mail issue subscribers, rework the function
1 parent 42ada74 commit d68421f

File tree

1 file changed

+65
-49
lines changed

1 file changed

+65
-49
lines changed

services/mailer/mail_issue.go

Lines changed: 65 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010
"code.gitea.io/gitea/models"
1111
"code.gitea.io/gitea/modules/log"
1212
"code.gitea.io/gitea/modules/references"
13-
14-
"github.com/unknwon/com"
1513
)
1614

1715
func fallbackMailSubject(issue *models.Issue) string {
@@ -24,64 +22,70 @@ func fallbackMailSubject(issue *models.Issue) string {
2422
// 2. Users who are not in 1. but get mentioned in current issue/comment.
2523
func mailIssueCommentToParticipants(issue *models.Issue, doer *models.User, actionType models.ActionType, content string, comment *models.Comment, mentions []string) error {
2624

27-
watchers, err := models.GetWatchers(issue.RepoID)
25+
// =========== Repo watchers ===========
26+
// *Watch
27+
rwatchers, err := models.GetWatchers(issue.RepoID)
2828
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)
3030
}
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)
3236
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)
3438
}
3539

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()
3948
if err != nil {
40-
return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
49+
return fmt.Errorf("GetIssueWatchers(%d): %v", issue.ID, err)
4150
}
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)
4457
}
4558

46-
// Assignees must receive any communications
59+
// =========== Assignees ===========
60+
// []*User
4761
assignees, err := models.GetAssigneesByIssue(issue)
4862
if err != nil {
4963
return err
5064
}
5165

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)
5671
}
5772

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)
6475

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
7278

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)
8285

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)
8589
}
8690

8791
if err := issue.LoadRepo(); err != nil {
@@ -92,15 +96,13 @@ func mailIssueCommentToParticipants(issue *models.Issue, doer *models.User, acti
9296
SendIssueCommentMail(issue, doer, actionType, content, comment, []string{to})
9397
}
9498

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)
101105
}
102-
103-
tos = append(tos, mentions[i])
104106
}
105107

106108
emails := models.GetUserEmailsByNames(tos)
@@ -112,6 +114,20 @@ func mailIssueCommentToParticipants(issue *models.Issue, doer *models.User, acti
112114
return nil
113115
}
114116

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+
115131
// MailParticipants sends new issue thread created emails to repository watchers
116132
// and mentioned people.
117133
func MailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType) error {

0 commit comments

Comments
 (0)