Mail assignee when issue/pull request is assigned (#8546)
* Send email to assigned user * Only send mail if enabled * Mail also when assigned through API * Need to refactor functions from models to issue service * Refer to issue index rather than ID * Disable email notifications completly at initalization if global disable * Check of user enbled mail shall be in mail notification function only * Initialize notifications from routers init function. * Use the assigned comment when sending assigned mail * Refactor so that assignees always added as separate step when new issue/pr. * Check error from AddAssignees * Check if user can be assiged to issue or pull request * Missing return * Refactor of CanBeAssigned check. CanBeAssigned shall have same check as UI. * Clarify function names (toggle rather than update/change), and clean up. * Fix review comments. * Flash error if assignees was not added when creating issue/pr * Generate error if assignee users doesn't exist
This commit is contained in:
parent
c34e58fc00
commit
6aa3f8bc29
23 changed files with 333 additions and 216 deletions
|
@ -9,12 +9,13 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// NewIssue creates new issue with labels for repository.
|
||||
func NewIssue(repo *models.Repository, issue *models.Issue, labelIDs []int64, assigneeIDs []int64, uuids []string) error {
|
||||
if err := models.NewIssue(repo, issue, labelIDs, assigneeIDs, uuids); err != nil {
|
||||
func NewIssue(repo *models.Repository, issue *models.Issue, labelIDs []int64, uuids []string) error {
|
||||
if err := models.NewIssue(repo, issue, labelIDs, uuids); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -96,3 +97,104 @@ func ChangeTitle(issue *models.Issue, doer *models.User, title string) (err erro
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAssignees is a helper function to add or delete one or multiple issue assignee(s)
|
||||
// Deleting is done the GitHub way (quote from their api documentation):
|
||||
// https://developer.github.com/v3/issues/#edit-an-issue
|
||||
// "assignees" (array): Logins for Users to assign to this issue.
|
||||
// Pass one or more user logins to replace the set of assignees on this Issue.
|
||||
// Send an empty array ([]) to clear all assignees from the Issue.
|
||||
func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees []string, doer *models.User) (err error) {
|
||||
var allNewAssignees []*models.User
|
||||
|
||||
// Keep the old assignee thingy for compatibility reasons
|
||||
if oneAssignee != "" {
|
||||
// Prevent double adding assignees
|
||||
var isDouble bool
|
||||
for _, assignee := range multipleAssignees {
|
||||
if assignee == oneAssignee {
|
||||
isDouble = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isDouble {
|
||||
multipleAssignees = append(multipleAssignees, oneAssignee)
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through all assignees to add them
|
||||
for _, assigneeName := range multipleAssignees {
|
||||
assignee, err := models.GetUserByName(assigneeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allNewAssignees = append(allNewAssignees, assignee)
|
||||
}
|
||||
|
||||
// Delete all old assignees not passed
|
||||
if err = models.DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add all new assignees
|
||||
// Update the assignee. The function will check if the user exists, is already
|
||||
// assigned (which he shouldn't as we deleted all assignees before) and
|
||||
// has access to the repo.
|
||||
for _, assignee := range allNewAssignees {
|
||||
// Extra method to prevent double adding (which would result in removing)
|
||||
err = AddAssigneeIfNotAssigned(issue, doer, assignee.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddAssigneeIfNotAssigned adds an assignee only if he isn't already assigned to the issue.
|
||||
// Also checks for access of assigned user
|
||||
func AddAssigneeIfNotAssigned(issue *models.Issue, doer *models.User, assigneeID int64) (err error) {
|
||||
assignee, err := models.GetUserByID(assigneeID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the user is already assigned
|
||||
isAssigned, err := models.IsUserAssignedToIssue(issue, assignee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isAssigned {
|
||||
// nothing to to
|
||||
return nil
|
||||
}
|
||||
|
||||
valid, err := models.CanBeAssigned(assignee, issue.Repo, issue.IsPull)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !valid {
|
||||
return models.ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: issue.Repo.Name}
|
||||
}
|
||||
|
||||
removed, comment, err := issue.ToggleAssignee(doer, assigneeID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
notification.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddAssignees adds a list of assignes (from IDs) to an issue
|
||||
func AddAssignees(issue *models.Issue, doer *models.User, assigneeIDs []int64) (err error) {
|
||||
for _, assigneeID := range assigneeIDs {
|
||||
if err = AddAssigneeIfNotAssigned(issue, doer, assigneeID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -28,8 +28,9 @@ const (
|
|||
mailAuthResetPassword base.TplName = "auth/reset_passwd"
|
||||
mailAuthRegisterNotify base.TplName = "auth/register_notify"
|
||||
|
||||
mailIssueComment base.TplName = "issue/comment"
|
||||
mailIssueMention base.TplName = "issue/mention"
|
||||
mailIssueComment base.TplName = "issue/comment"
|
||||
mailIssueMention base.TplName = "issue/mention"
|
||||
mailIssueAssigned base.TplName = "issue/assigned"
|
||||
|
||||
mailNotifyCollaborator base.TplName = "notify/collaborator"
|
||||
)
|
||||
|
@ -183,6 +184,7 @@ func composeIssueCommentMessage(issue *models.Issue, doer *models.User, content
|
|||
data = composeTplData(subject, body, issue.HTMLURL())
|
||||
}
|
||||
data["Doer"] = doer
|
||||
data["Issue"] = issue
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
|
@ -220,3 +222,8 @@ func SendIssueMentionMail(issue *models.Issue, doer *models.User, content string
|
|||
}
|
||||
SendAsync(composeIssueCommentMessage(issue, doer, content, comment, mailIssueMention, tos, "issue mention"))
|
||||
}
|
||||
|
||||
// SendIssueAssignedMail composes and sends issue assigned email
|
||||
func SendIssueAssignedMail(issue *models.Issue, doer *models.User, content string, comment *models.Comment, tos []string) {
|
||||
SendAsync(composeIssueCommentMessage(issue, doer, content, comment, mailIssueAssigned, tos, "issue assigned"))
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/references"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
@ -24,9 +23,6 @@ func mailSubject(issue *models.Issue) string {
|
|||
// 1. Repository watchers and users who are participated in comments.
|
||||
// 2. Users who are not in 1. but get mentioned in current issue/comment.
|
||||
func mailIssueCommentToParticipants(issue *models.Issue, doer *models.User, content string, comment *models.Comment, mentions []string) error {
|
||||
if !setting.Service.EnableNotifyMail {
|
||||
return nil
|
||||
}
|
||||
|
||||
watchers, err := models.GetWatchers(issue.RepoID)
|
||||
if err != nil {
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
)
|
||||
|
||||
// NewPullRequest creates new pull request with labels for repository.
|
||||
func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int64, uuids []string, pr *models.PullRequest, patch []byte, assigneeIDs []int64) error {
|
||||
if err := models.NewPullRequest(repo, pull, labelIDs, uuids, pr, patch, assigneeIDs); err != nil {
|
||||
func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int64, uuids []string, pr *models.PullRequest, patch []byte) error {
|
||||
if err := models.NewPullRequest(repo, pull, labelIDs, uuids, pr, patch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue