Send notifications for mentions in pulls, issues, (code-)comments (#14218)
Fixes #14187: mention handling extracted from email notification code Fixes #14013: add notification for mentions in pull request code comments Fixes #13450: Not receiving any emails with setting "Only Email on Mention"
This commit is contained in:
parent
ac88b0ee83
commit
e6acce649b
15 changed files with 205 additions and 88 deletions
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/references"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -1848,6 +1849,19 @@ func (issue *Issue) updateClosedNum(e Engine) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindAndUpdateIssueMentions finds users mentioned in the given content string, and saves them in the database.
|
||||||
|
func (issue *Issue) FindAndUpdateIssueMentions(ctx DBContext, doer *User, content string) (mentions []*User, err error) {
|
||||||
|
rawMentions := references.FindAllMentionsMarkdown(content)
|
||||||
|
mentions, err = issue.ResolveMentionsByVisibility(ctx, doer, rawMentions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
|
||||||
|
}
|
||||||
|
if err = UpdateIssueMentions(ctx, issue.ID, mentions); err != nil {
|
||||||
|
return nil, fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that
|
// ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that
|
||||||
// don't have access to reading it. Teams are expanded into their users, but organizations are ignored.
|
// don't have access to reading it. Teams are expanded into their users, but organizations are ignored.
|
||||||
func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, mentions []string) (users []*User, err error) {
|
func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, mentions []string) (users []*User, err error) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ func NewNotifier() base.Notifier {
|
||||||
return &actionNotifier{}
|
return &actionNotifier{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *actionNotifier) NotifyNewIssue(issue *models.Issue) {
|
func (a *actionNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
if err := issue.LoadPoster(); err != nil {
|
if err := issue.LoadPoster(); err != nil {
|
||||||
log.Error("issue.LoadPoster: %v", err)
|
log.Error("issue.LoadPoster: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -88,7 +88,7 @@ func (a *actionNotifier) NotifyIssueChangeStatus(doer *models.User, issue *model
|
||||||
|
|
||||||
// NotifyCreateIssueComment notifies comment on an issue to notifiers
|
// NotifyCreateIssueComment notifies comment on an issue to notifiers
|
||||||
func (a *actionNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func (a *actionNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
act := &models.Action{
|
act := &models.Action{
|
||||||
ActUserID: doer.ID,
|
ActUserID: doer.ID,
|
||||||
ActUser: doer,
|
ActUser: doer,
|
||||||
|
@ -120,7 +120,7 @@ func (a *actionNotifier) NotifyCreateIssueComment(doer *models.User, repo *model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
|
func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*models.User) {
|
||||||
if err := pull.LoadIssue(); err != nil {
|
if err := pull.LoadIssue(); err != nil {
|
||||||
log.Error("pull.LoadIssue: %v", err)
|
log.Error("pull.LoadIssue: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -203,7 +203,7 @@ func (a *actionNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
|
func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User) {
|
||||||
if err := review.LoadReviewer(); err != nil {
|
if err := review.LoadReviewer(); err != nil {
|
||||||
log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err)
|
log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Notifier interface {
|
||||||
NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string)
|
NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string)
|
||||||
NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string)
|
NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string)
|
||||||
|
|
||||||
NotifyNewIssue(*models.Issue)
|
NotifyNewIssue(issue *models.Issue, mentions []*models.User)
|
||||||
NotifyIssueChangeStatus(*models.User, *models.Issue, *models.Comment, bool)
|
NotifyIssueChangeStatus(*models.User, *models.Issue, *models.Comment, bool)
|
||||||
NotifyIssueChangeMilestone(doer *models.User, issue *models.Issue, oldMilestoneID int64)
|
NotifyIssueChangeMilestone(doer *models.User, issue *models.Issue, oldMilestoneID int64)
|
||||||
NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment)
|
NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment)
|
||||||
|
@ -32,15 +32,16 @@ type Notifier interface {
|
||||||
NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
|
NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
|
||||||
addedLabels []*models.Label, removedLabels []*models.Label)
|
addedLabels []*models.Label, removedLabels []*models.Label)
|
||||||
|
|
||||||
NotifyNewPullRequest(*models.PullRequest)
|
NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User)
|
||||||
NotifyMergePullRequest(*models.PullRequest, *models.User)
|
NotifyMergePullRequest(*models.PullRequest, *models.User)
|
||||||
NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest)
|
NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest)
|
||||||
NotifyPullRequestReview(*models.PullRequest, *models.Review, *models.Comment)
|
NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User)
|
||||||
|
NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User)
|
||||||
NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string)
|
NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string)
|
||||||
NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment)
|
NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment)
|
||||||
|
|
||||||
NotifyCreateIssueComment(*models.User, *models.Repository,
|
NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
*models.Issue, *models.Comment)
|
issue *models.Issue, comment *models.Comment, mentions []*models.User)
|
||||||
NotifyUpdateComment(*models.User, *models.Comment, string)
|
NotifyUpdateComment(*models.User, *models.Comment, string)
|
||||||
NotifyDeleteComment(*models.User, *models.Comment)
|
NotifyDeleteComment(*models.User, *models.Comment)
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,11 @@ func (*NullNotifier) Run() {
|
||||||
|
|
||||||
// NotifyCreateIssueComment places a place holder function
|
// NotifyCreateIssueComment places a place holder function
|
||||||
func (*NullNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func (*NullNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewIssue places a place holder function
|
// NotifyNewIssue places a place holder function
|
||||||
func (*NullNotifier) NotifyNewIssue(issue *models.Issue) {
|
func (*NullNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyIssueChangeStatus places a place holder function
|
// NotifyIssueChangeStatus places a place holder function
|
||||||
|
@ -35,11 +35,15 @@ func (*NullNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Is
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewPullRequest places a place holder function
|
// NotifyNewPullRequest places a place holder function
|
||||||
func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
|
func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestReview places a place holder function
|
// NotifyPullRequestReview places a place holder function
|
||||||
func (*NullNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment) {
|
func (*NullNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*models.User) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyPullRequestCodeComment places a place holder function
|
||||||
|
func (*NullNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyMergePullRequest places a place holder function
|
// NotifyMergePullRequest places a place holder function
|
||||||
|
|
|
@ -30,7 +30,7 @@ func NewNotifier() base.Notifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func (r *indexerNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
if comment.Type == models.CommentTypeComment {
|
if comment.Type == models.CommentTypeComment {
|
||||||
if issue.Comments == nil {
|
if issue.Comments == nil {
|
||||||
if err := issue.LoadDiscussComments(); err != nil {
|
if err := issue.LoadDiscussComments(); err != nil {
|
||||||
|
@ -45,11 +45,11 @@ func (r *indexerNotifier) NotifyCreateIssueComment(doer *models.User, repo *mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyNewIssue(issue *models.Issue) {
|
func (r *indexerNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
issue_indexer.UpdateIssueIndexer(issue)
|
issue_indexer.UpdateIssueIndexer(issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexerNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
|
func (r *indexerNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
|
||||||
issue_indexer.UpdateIssueIndexer(pr.Issue)
|
issue_indexer.UpdateIssueIndexer(pr.Issue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ func NewNotifier() base.Notifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
var act models.ActionType
|
var act models.ActionType
|
||||||
if comment.Type == models.CommentTypeClose {
|
if comment.Type == models.CommentTypeClose {
|
||||||
act = models.ActionCloseIssue
|
act = models.ActionCloseIssue
|
||||||
|
@ -41,13 +41,13 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.
|
||||||
act = 0
|
act = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mailer.MailParticipantsComment(comment, act, issue); err != nil {
|
if err := mailer.MailParticipantsComment(comment, act, issue, mentions); err != nil {
|
||||||
log.Error("MailParticipantsComment: %v", err)
|
log.Error("MailParticipantsComment: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) {
|
func (m *mailNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue); err != nil {
|
if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue, mentions); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,18 +69,18 @@ func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mailer.MailParticipants(issue, doer, actionType); err != nil {
|
if err := mailer.MailParticipants(issue, doer, actionType, nil); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
|
func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
|
||||||
if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest); err != nil {
|
if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest, mentions); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment) {
|
func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*models.User) {
|
||||||
var act models.ActionType
|
var act models.ActionType
|
||||||
if comment.Type == models.CommentTypeClose {
|
if comment.Type == models.CommentTypeClose {
|
||||||
act = models.ActionCloseIssue
|
act = models.ActionCloseIssue
|
||||||
|
@ -89,11 +89,17 @@ func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models
|
||||||
} else if comment.Type == models.CommentTypeComment {
|
} else if comment.Type == models.CommentTypeComment {
|
||||||
act = models.ActionCommentPull
|
act = models.ActionCommentPull
|
||||||
}
|
}
|
||||||
if err := mailer.MailParticipantsComment(comment, act, pr.Issue); err != nil {
|
if err := mailer.MailParticipantsComment(comment, act, pr.Issue, mentions); err != nil {
|
||||||
log.Error("MailParticipantsComment: %v", err)
|
log.Error("MailParticipantsComment: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User) {
|
||||||
|
if err := mailer.MailMentionsComment(pr, comment, mentions); err != nil {
|
||||||
|
log.Error("MailMentionsComment: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
|
func (m *mailNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
|
||||||
// mail only sent to added assignees and not self-assignee
|
// mail only sent to added assignees and not self-assignee
|
||||||
if !removed && doer.ID != assignee.ID && assignee.EmailNotifications() == models.EmailNotificationsEnabled {
|
if !removed && doer.ID != assignee.ID && assignee.EmailNotifications() == models.EmailNotificationsEnabled {
|
||||||
|
@ -115,7 +121,7 @@ func (m *mailNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *mode
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pr.Issue.Content = ""
|
pr.Issue.Content = ""
|
||||||
if err := mailer.MailParticipants(pr.Issue, doer, models.ActionMergePullRequest); err != nil {
|
if err := mailer.MailParticipants(pr.Issue, doer, models.ActionMergePullRequest, nil); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +149,7 @@ func (m *mailNotifier) NotifyPullRequestPushCommits(doer *models.User, pr *model
|
||||||
}
|
}
|
||||||
comment.Content = ""
|
comment.Content = ""
|
||||||
|
|
||||||
m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment)
|
m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mailNotifier) NotifyNewRelease(rel *models.Release) {
|
func (m *mailNotifier) NotifyNewRelease(rel *models.Release) {
|
||||||
|
|
|
@ -39,16 +39,16 @@ func NewContext() {
|
||||||
|
|
||||||
// NotifyCreateIssueComment notifies issue comment related message to notifiers
|
// NotifyCreateIssueComment notifies issue comment related message to notifiers
|
||||||
func NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyCreateIssueComment(doer, repo, issue, comment)
|
notifier.NotifyCreateIssueComment(doer, repo, issue, comment, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewIssue notifies new issue to notifiers
|
// NotifyNewIssue notifies new issue to notifiers
|
||||||
func NotifyNewIssue(issue *models.Issue) {
|
func NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyNewIssue(issue)
|
notifier.NotifyNewIssue(issue, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +67,9 @@ func NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyNewPullRequest notifies new pull request to notifiers
|
// NotifyNewPullRequest notifies new pull request to notifiers
|
||||||
func NotifyNewPullRequest(pr *models.PullRequest) {
|
func NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyNewPullRequest(pr)
|
notifier.NotifyNewPullRequest(pr, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +81,16 @@ func NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPullRequestReview notifies new pull request review
|
// NotifyPullRequestReview notifies new pull request review
|
||||||
func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
|
func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User) {
|
||||||
for _, notifier := range notifiers {
|
for _, notifier := range notifiers {
|
||||||
notifier.NotifyPullRequestReview(pr, review, comment)
|
notifier.NotifyPullRequestReview(pr, review, comment, mentions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyPullRequestCodeComment notifies new pull request code comment
|
||||||
|
func NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User) {
|
||||||
|
for _, notifier := range notifiers {
|
||||||
|
notifier.NotifyPullRequestCodeComment(pr, comment, mentions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (ns *notificationService) Run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func (ns *notificationService) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
var opts = issueNotificationOpts{
|
var opts = issueNotificationOpts{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
NotificationAuthorID: doer.ID,
|
NotificationAuthorID: doer.ID,
|
||||||
|
@ -60,13 +60,31 @@ func (ns *notificationService) NotifyCreateIssueComment(doer *models.User, repo
|
||||||
opts.CommentID = comment.ID
|
opts.CommentID = comment.ID
|
||||||
}
|
}
|
||||||
_ = ns.issueQueue.Push(opts)
|
_ = ns.issueQueue.Push(opts)
|
||||||
|
for _, mention := range mentions {
|
||||||
|
var opts = issueNotificationOpts{
|
||||||
|
IssueID: issue.ID,
|
||||||
|
NotificationAuthorID: doer.ID,
|
||||||
|
ReceiverID: mention.ID,
|
||||||
|
}
|
||||||
|
if comment != nil {
|
||||||
|
opts.CommentID = comment.ID
|
||||||
|
}
|
||||||
|
_ = ns.issueQueue.Push(opts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyNewIssue(issue *models.Issue) {
|
func (ns *notificationService) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
_ = ns.issueQueue.Push(issueNotificationOpts{
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
NotificationAuthorID: issue.Poster.ID,
|
NotificationAuthorID: issue.Poster.ID,
|
||||||
})
|
})
|
||||||
|
for _, mention := range mentions {
|
||||||
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
||||||
|
IssueID: issue.ID,
|
||||||
|
NotificationAuthorID: issue.Poster.ID,
|
||||||
|
ReceiverID: mention.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
|
func (ns *notificationService) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
|
||||||
|
@ -83,7 +101,7 @@ func (ns *notificationService) NotifyMergePullRequest(pr *models.PullRequest, do
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest) {
|
func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
|
||||||
if err := pr.LoadIssue(); err != nil {
|
if err := pr.LoadIssue(); err != nil {
|
||||||
log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
|
log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
|
||||||
return
|
return
|
||||||
|
@ -92,9 +110,16 @@ func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest) {
|
||||||
IssueID: pr.Issue.ID,
|
IssueID: pr.Issue.ID,
|
||||||
NotificationAuthorID: pr.Issue.PosterID,
|
NotificationAuthorID: pr.Issue.PosterID,
|
||||||
})
|
})
|
||||||
|
for _, mention := range mentions {
|
||||||
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
||||||
|
IssueID: pr.Issue.ID,
|
||||||
|
NotificationAuthorID: pr.Issue.PosterID,
|
||||||
|
ReceiverID: mention.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment) {
|
func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment, mentions []*models.User) {
|
||||||
var opts = issueNotificationOpts{
|
var opts = issueNotificationOpts{
|
||||||
IssueID: pr.Issue.ID,
|
IssueID: pr.Issue.ID,
|
||||||
NotificationAuthorID: r.Reviewer.ID,
|
NotificationAuthorID: r.Reviewer.ID,
|
||||||
|
@ -103,6 +128,28 @@ func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r
|
||||||
opts.CommentID = c.ID
|
opts.CommentID = c.ID
|
||||||
}
|
}
|
||||||
_ = ns.issueQueue.Push(opts)
|
_ = ns.issueQueue.Push(opts)
|
||||||
|
for _, mention := range mentions {
|
||||||
|
var opts = issueNotificationOpts{
|
||||||
|
IssueID: pr.Issue.ID,
|
||||||
|
NotificationAuthorID: r.Reviewer.ID,
|
||||||
|
ReceiverID: mention.ID,
|
||||||
|
}
|
||||||
|
if c != nil {
|
||||||
|
opts.CommentID = c.ID
|
||||||
|
}
|
||||||
|
_ = ns.issueQueue.Push(opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *notificationService) NotifyPullRequestCodeComment(pr *models.PullRequest, c *models.Comment, mentions []*models.User) {
|
||||||
|
for _, mention := range mentions {
|
||||||
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
||||||
|
IssueID: pr.Issue.ID,
|
||||||
|
NotificationAuthorID: c.Poster.ID,
|
||||||
|
CommentID: c.ID,
|
||||||
|
ReceiverID: mention.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *notificationService) NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
|
func (ns *notificationService) NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
|
||||||
|
|
|
@ -261,7 +261,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(doer *models.User, issue *mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
|
func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
|
||||||
if err := issue.LoadRepo(); err != nil {
|
if err := issue.LoadRepo(); err != nil {
|
||||||
log.Error("issue.LoadRepo: %v", err)
|
log.Error("issue.LoadRepo: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -283,7 +283,7 @@ func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
|
func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*models.User) {
|
||||||
if err := pull.LoadIssue(); err != nil {
|
if err := pull.LoadIssue(); err != nil {
|
||||||
log.Error("pull.LoadIssue: %v", err)
|
log.Error("pull.LoadIssue: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -399,7 +399,7 @@ func (m *webhookNotifier) NotifyUpdateComment(doer *models.User, c *models.Comme
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
func (m *webhookNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
|
||||||
issue *models.Issue, comment *models.Comment) {
|
issue *models.Issue, comment *models.Comment, mentions []*models.User) {
|
||||||
mode, _ := models.AccessLevel(doer, repo)
|
mode, _ := models.AccessLevel(doer, repo)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
@ -651,7 +651,7 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *models.User,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
|
func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User) {
|
||||||
var reviewHookType models.HookEventType
|
var reviewHookType models.HookEventType
|
||||||
|
|
||||||
switch review.Type {
|
switch review.Type {
|
||||||
|
|
|
@ -22,8 +22,11 @@ func CreateIssueComment(doer *models.User, repo *models.Repository, issue *model
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
mentions, err := issue.FindAndUpdateIssueMentions(models.DefaultDBContext(), doer, comment.Content)
|
||||||
notification.NotifyCreateIssueComment(doer, repo, issue, comment)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
notification.NotifyCreateIssueComment(doer, repo, issue, comment, mentions)
|
||||||
|
|
||||||
return comment, nil
|
return comment, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,12 @@ func NewIssue(repo *models.Repository, issue *models.Issue, labelIDs []int64, uu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.NotifyNewIssue(issue)
|
mentions, err := issue.FindAndUpdateIssueMentions(models.DefaultDBContext(), issue.Poster, issue.Content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.NotifyNewIssue(issue, mentions)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,31 +5,20 @@
|
||||||
package mailer
|
package mailer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/references"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MailParticipantsComment sends new comment emails to repository watchers
|
// MailParticipantsComment sends new comment emails to repository watchers
|
||||||
// and mentioned people.
|
// and mentioned people.
|
||||||
func MailParticipantsComment(c *models.Comment, opType models.ActionType, issue *models.Issue) error {
|
func MailParticipantsComment(c *models.Comment, opType models.ActionType, issue *models.Issue, mentions []*models.User) error {
|
||||||
return mailParticipantsComment(models.DefaultDBContext(), c, opType, issue)
|
return mailParticipantsComment(c, opType, issue, mentions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mailParticipantsComment(ctx models.DBContext, c *models.Comment, opType models.ActionType, issue *models.Issue) (err error) {
|
func mailParticipantsComment(c *models.Comment, opType models.ActionType, issue *models.Issue, mentions []*models.User) (err error) {
|
||||||
rawMentions := references.FindAllMentionsMarkdown(c.Content)
|
mentionedIDs := make([]int64, len(mentions))
|
||||||
userMentions, err := issue.ResolveMentionsByVisibility(ctx, c.Poster, rawMentions)
|
for i, u := range mentions {
|
||||||
if err != nil {
|
mentionedIDs[i] = u.ID
|
||||||
return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", c.IssueID, err)
|
|
||||||
}
|
|
||||||
if err = models.UpdateIssueMentions(ctx, c.IssueID, userMentions); err != nil {
|
|
||||||
return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err)
|
|
||||||
}
|
|
||||||
mentions := make([]int64, len(userMentions))
|
|
||||||
for i, u := range userMentions {
|
|
||||||
mentions[i] = u.ID
|
|
||||||
}
|
}
|
||||||
if err = mailIssueCommentToParticipants(
|
if err = mailIssueCommentToParticipants(
|
||||||
&mailCommentContext{
|
&mailCommentContext{
|
||||||
|
@ -38,8 +27,29 @@ func mailParticipantsComment(ctx models.DBContext, c *models.Comment, opType mod
|
||||||
ActionType: opType,
|
ActionType: opType,
|
||||||
Content: c.Content,
|
Content: c.Content,
|
||||||
Comment: c,
|
Comment: c,
|
||||||
}, mentions); err != nil {
|
}, mentionedIDs); err != nil {
|
||||||
log.Error("mailIssueCommentToParticipants: %v", err)
|
log.Error("mailIssueCommentToParticipants: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MailMentionsComment sends email to users mentioned in a code comment
|
||||||
|
func MailMentionsComment(pr *models.PullRequest, c *models.Comment, mentions []*models.User) (err error) {
|
||||||
|
mentionedIDs := make([]int64, len(mentions))
|
||||||
|
for i, u := range mentions {
|
||||||
|
mentionedIDs[i] = u.ID
|
||||||
|
}
|
||||||
|
visited := make(map[int64]bool, len(mentions)+1)
|
||||||
|
visited[c.Poster.ID] = true
|
||||||
|
if err = mailIssueCommentBatch(
|
||||||
|
&mailCommentContext{
|
||||||
|
Issue: pr.Issue,
|
||||||
|
Doer: c.Poster,
|
||||||
|
ActionType: models.ActionCommentPull,
|
||||||
|
Content: c.Content,
|
||||||
|
Comment: c,
|
||||||
|
}, mentionedIDs, visited, true); err != nil {
|
||||||
|
log.Error("mailIssueCommentBatch: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/references"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func fallbackMailSubject(issue *models.Issue) string {
|
func fallbackMailSubject(issue *models.Issue) string {
|
||||||
|
@ -80,6 +79,12 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []int64) e
|
||||||
|
|
||||||
// Avoid mailing the doer
|
// Avoid mailing the doer
|
||||||
visited[ctx.Doer.ID] = true
|
visited[ctx.Doer.ID] = true
|
||||||
|
|
||||||
|
// =========== Mentions ===========
|
||||||
|
if err = mailIssueCommentBatch(ctx, mentions, visited, true); err != nil {
|
||||||
|
return fmt.Errorf("mailIssueCommentBatch() mentions: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid mailing explicit unwatched
|
// Avoid mailing explicit unwatched
|
||||||
ids, err = models.GetIssueWatchersIDs(ctx.Issue.ID, false)
|
ids, err = models.GetIssueWatchersIDs(ctx.Issue.ID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -93,11 +98,6 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []int64) e
|
||||||
return fmt.Errorf("mailIssueCommentBatch(): %v", err)
|
return fmt.Errorf("mailIssueCommentBatch(): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========== Mentions ===========
|
|
||||||
if err = mailIssueCommentBatch(ctx, mentions, visited, true); err != nil {
|
|
||||||
return fmt.Errorf("mailIssueCommentBatch() mentions: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,22 +145,14 @@ func mailIssueCommentBatch(ctx *mailCommentContext, ids []int64, visited map[int
|
||||||
|
|
||||||
// MailParticipants sends new issue thread created emails to repository watchers
|
// MailParticipants sends new issue thread created emails to repository watchers
|
||||||
// and mentioned people.
|
// and mentioned people.
|
||||||
func MailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType) error {
|
func MailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType, mentions []*models.User) error {
|
||||||
return mailParticipants(models.DefaultDBContext(), issue, doer, opType)
|
return mailParticipants(issue, doer, opType, mentions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mailParticipants(ctx models.DBContext, issue *models.Issue, doer *models.User, opType models.ActionType) (err error) {
|
func mailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType, mentions []*models.User) (err error) {
|
||||||
rawMentions := references.FindAllMentionsMarkdown(issue.Content)
|
mentionedIDs := make([]int64, len(mentions))
|
||||||
userMentions, err := issue.ResolveMentionsByVisibility(ctx, doer, rawMentions)
|
for i, u := range mentions {
|
||||||
if err != nil {
|
mentionedIDs[i] = u.ID
|
||||||
return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", issue.ID, err)
|
|
||||||
}
|
|
||||||
if err = models.UpdateIssueMentions(ctx, issue.ID, userMentions); err != nil {
|
|
||||||
return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
|
|
||||||
}
|
|
||||||
mentions := make([]int64, len(userMentions))
|
|
||||||
for i, u := range userMentions {
|
|
||||||
mentions[i] = u.ID
|
|
||||||
}
|
}
|
||||||
if err = mailIssueCommentToParticipants(
|
if err = mailIssueCommentToParticipants(
|
||||||
&mailCommentContext{
|
&mailCommentContext{
|
||||||
|
@ -169,7 +161,7 @@ func mailParticipants(ctx models.DBContext, issue *models.Issue, doer *models.Us
|
||||||
ActionType: opType,
|
ActionType: opType,
|
||||||
Content: issue.Content,
|
Content: issue.Content,
|
||||||
Comment: nil,
|
Comment: nil,
|
||||||
}, mentions); err != nil {
|
}, mentionedIDs); err != nil {
|
||||||
log.Error("mailIssueCommentToParticipants: %v", err)
|
log.Error("mailIssueCommentToParticipants: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -53,7 +53,12 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.NotifyNewPullRequest(pr)
|
mentions, err := pull.FindAndUpdateIssueMentions(models.DefaultDBContext(), pull.Poster, pull.Content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.NotifyNewPullRequest(pr, mentions)
|
||||||
|
|
||||||
// add first push codes comment
|
// add first push codes comment
|
||||||
baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
||||||
|
|
|
@ -57,7 +57,12 @@ func CreateCodeComment(doer *models.User, gitRepo *git.Repository, issue *models
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.NotifyCreateIssueComment(doer, issue.Repo, issue, comment)
|
mentions, err := issue.FindAndUpdateIssueMentions(models.DefaultDBContext(), doer, comment.Content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.NotifyCreateIssueComment(doer, issue.Repo, issue, comment, mentions)
|
||||||
|
|
||||||
return comment, nil
|
return comment, nil
|
||||||
}
|
}
|
||||||
|
@ -226,7 +231,25 @@ func SubmitReview(doer *models.User, gitRepo *git.Repository, issue *models.Issu
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.NotifyPullRequestReview(pr, review, comm)
|
ctx := models.DefaultDBContext()
|
||||||
|
mentions, err := issue.FindAndUpdateIssueMentions(ctx, doer, comm.Content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.NotifyPullRequestReview(pr, review, comm, mentions)
|
||||||
|
|
||||||
|
for _, lines := range review.CodeComments {
|
||||||
|
for _, comments := range lines {
|
||||||
|
for _, codeComment := range comments {
|
||||||
|
mentions, err := issue.FindAndUpdateIssueMentions(ctx, doer, codeComment.Content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
notification.NotifyPullRequestCodeComment(pr, codeComment, mentions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return review, comm, nil
|
return review, comm, nil
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue