mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-12-12 14:31:58 +01:00
6be1d71e2b
Backport #22627 Adding the related comment to the issue and pull request status change in the UI notifications allows to navigate directly to the specific event in its dedicated view, easing the reading of last comments and to the editor for additional comments if desired. Co-authored-by: Felipe Leopoldo Sologuren Gutiérrez <fsologureng@users.noreply.github.com>
245 lines
7.4 KiB
Go
245 lines
7.4 KiB
Go
// Copyright 2018 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 ui
|
|
|
|
import (
|
|
activities_model "code.gitea.io/gitea/models/activities"
|
|
"code.gitea.io/gitea/models/db"
|
|
issues_model "code.gitea.io/gitea/models/issues"
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/container"
|
|
"code.gitea.io/gitea/modules/graceful"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/notification/base"
|
|
"code.gitea.io/gitea/modules/queue"
|
|
)
|
|
|
|
type (
|
|
notificationService struct {
|
|
base.NullNotifier
|
|
issueQueue queue.Queue
|
|
}
|
|
|
|
issueNotificationOpts struct {
|
|
IssueID int64
|
|
CommentID int64
|
|
NotificationAuthorID int64
|
|
ReceiverID int64 // 0 -- ALL Watcher
|
|
}
|
|
)
|
|
|
|
var _ base.Notifier = ¬ificationService{}
|
|
|
|
// NewNotifier create a new notificationService notifier
|
|
func NewNotifier() base.Notifier {
|
|
ns := ¬ificationService{}
|
|
ns.issueQueue = queue.CreateQueue("notification-service", ns.handle, issueNotificationOpts{})
|
|
return ns
|
|
}
|
|
|
|
func (ns *notificationService) handle(data ...queue.Data) []queue.Data {
|
|
for _, datum := range data {
|
|
opts := datum.(issueNotificationOpts)
|
|
if err := activities_model.CreateOrUpdateIssueNotifications(opts.IssueID, opts.CommentID, opts.NotificationAuthorID, opts.ReceiverID); err != nil {
|
|
log.Error("Was unable to create issue notification: %v", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ns *notificationService) Run() {
|
|
graceful.GetManager().RunWithShutdownFns(ns.issueQueue.Run)
|
|
}
|
|
|
|
func (ns *notificationService) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
|
|
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
|
|
) {
|
|
opts := issueNotificationOpts{
|
|
IssueID: issue.ID,
|
|
NotificationAuthorID: doer.ID,
|
|
}
|
|
if comment != nil {
|
|
opts.CommentID = comment.ID
|
|
}
|
|
_ = ns.issueQueue.Push(opts)
|
|
for _, mention := range mentions {
|
|
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 *issues_model.Issue, mentions []*user_model.User) {
|
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
|
IssueID: issue.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 *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
|
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
|
IssueID: issue.ID,
|
|
NotificationAuthorID: doer.ID,
|
|
CommentID: actionComment.ID,
|
|
})
|
|
}
|
|
|
|
func (ns *notificationService) NotifyIssueChangeTitle(doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
|
|
if err := issue.LoadPullRequest(); err != nil {
|
|
log.Error("issue.LoadPullRequest: %v", err)
|
|
return
|
|
}
|
|
if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() {
|
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
|
IssueID: issue.ID,
|
|
NotificationAuthorID: doer.ID,
|
|
})
|
|
}
|
|
}
|
|
|
|
func (ns *notificationService) NotifyMergePullRequest(pr *issues_model.PullRequest, doer *user_model.User) {
|
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
|
IssueID: pr.Issue.ID,
|
|
NotificationAuthorID: doer.ID,
|
|
})
|
|
}
|
|
|
|
func (ns *notificationService) NotifyNewPullRequest(pr *issues_model.PullRequest, mentions []*user_model.User) {
|
|
if err := pr.LoadIssue(); err != nil {
|
|
log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
|
|
return
|
|
}
|
|
toNotify := make(container.Set[int64], 32)
|
|
repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID)
|
|
if err != nil {
|
|
log.Error("GetRepoWatchersIDs: %v", err)
|
|
return
|
|
}
|
|
for _, id := range repoWatchers {
|
|
toNotify.Add(id)
|
|
}
|
|
issueParticipants, err := issues_model.GetParticipantsIDsByIssueID(pr.IssueID)
|
|
if err != nil {
|
|
log.Error("GetParticipantsIDsByIssueID: %v", err)
|
|
return
|
|
}
|
|
for _, id := range issueParticipants {
|
|
toNotify.Add(id)
|
|
}
|
|
delete(toNotify, pr.Issue.PosterID)
|
|
for _, mention := range mentions {
|
|
toNotify.Add(mention.ID)
|
|
}
|
|
for receiverID := range toNotify {
|
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
|
IssueID: pr.Issue.ID,
|
|
NotificationAuthorID: pr.Issue.PosterID,
|
|
ReceiverID: receiverID,
|
|
})
|
|
}
|
|
}
|
|
|
|
func (ns *notificationService) NotifyPullRequestReview(pr *issues_model.PullRequest, r *issues_model.Review, c *issues_model.Comment, mentions []*user_model.User) {
|
|
opts := issueNotificationOpts{
|
|
IssueID: pr.Issue.ID,
|
|
NotificationAuthorID: r.Reviewer.ID,
|
|
}
|
|
if c != nil {
|
|
opts.CommentID = c.ID
|
|
}
|
|
_ = ns.issueQueue.Push(opts)
|
|
for _, mention := range mentions {
|
|
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 *issues_model.PullRequest, c *issues_model.Comment, mentions []*user_model.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 *user_model.User, pr *issues_model.PullRequest, comment *issues_model.Comment) {
|
|
opts := issueNotificationOpts{
|
|
IssueID: pr.IssueID,
|
|
NotificationAuthorID: doer.ID,
|
|
CommentID: comment.ID,
|
|
}
|
|
_ = ns.issueQueue.Push(opts)
|
|
}
|
|
|
|
func (ns *notificationService) NotifyPullRevieweDismiss(doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
|
|
opts := issueNotificationOpts{
|
|
IssueID: review.IssueID,
|
|
NotificationAuthorID: doer.ID,
|
|
CommentID: comment.ID,
|
|
}
|
|
_ = ns.issueQueue.Push(opts)
|
|
}
|
|
|
|
func (ns *notificationService) NotifyIssueChangeAssignee(doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
|
|
if !removed && doer.ID != assignee.ID {
|
|
opts := issueNotificationOpts{
|
|
IssueID: issue.ID,
|
|
NotificationAuthorID: doer.ID,
|
|
ReceiverID: assignee.ID,
|
|
}
|
|
|
|
if comment != nil {
|
|
opts.CommentID = comment.ID
|
|
}
|
|
|
|
_ = ns.issueQueue.Push(opts)
|
|
}
|
|
}
|
|
|
|
func (ns *notificationService) NotifyPullReviewRequest(doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
|
|
if isRequest {
|
|
opts := issueNotificationOpts{
|
|
IssueID: issue.ID,
|
|
NotificationAuthorID: doer.ID,
|
|
ReceiverID: reviewer.ID,
|
|
}
|
|
|
|
if comment != nil {
|
|
opts.CommentID = comment.ID
|
|
}
|
|
|
|
_ = ns.issueQueue.Push(opts)
|
|
}
|
|
}
|
|
|
|
func (ns *notificationService) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) {
|
|
if err := activities_model.CreateRepoTransferNotification(doer, newOwner, repo); err != nil {
|
|
log.Error("NotifyRepoPendingTransfer: %v", err)
|
|
}
|
|
}
|