1
1
mirror of https://github.com/go-gitea/gitea synced 2025-08-09 19:18:20 +00:00

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:
David Svantesson
2019-10-25 16:46:37 +02:00
committed by Lunny Xiao
parent c34e58fc00
commit 6aa3f8bc29
23 changed files with 333 additions and 216 deletions

View File

@@ -213,12 +213,31 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
}
return
}
// Check if the passed assignees is assignable
for _, aID := range assigneeIDs {
assignee, err := models.GetUserByID(aID)
if err != nil {
ctx.Error(500, "GetUserByID", err)
return
}
valid, err := models.CanBeAssigned(assignee, ctx.Repo.Repository, false)
if err != nil {
ctx.Error(500, "canBeAssigned", err)
return
}
if !valid {
ctx.Error(422, "canBeAssigned", models.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: ctx.Repo.Repository.Name})
return
}
}
} else {
// setting labels is not allowed if user is not a writer
form.Labels = make([]int64, 0)
}
if err := issue_service.NewIssue(ctx.Repo.Repository, issue, form.Labels, assigneeIDs, nil); err != nil {
if err := issue_service.NewIssue(ctx.Repo.Repository, issue, form.Labels, nil); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
return
@@ -227,6 +246,11 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
return
}
if err := issue_service.AddAssignees(issue, ctx.User, assigneeIDs); err != nil {
ctx.ServerError("AddAssignees", err)
return
}
notification.NotifyNewIssue(issue)
if form.Closed {
@@ -336,9 +360,9 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
oneAssignee = *form.Assignee
}
err = models.UpdateAPIAssignee(issue, oneAssignee, form.Assignees, ctx.User)
err = issue_service.UpdateAssignees(issue, oneAssignee, form.Assignees, ctx.User)
if err != nil {
ctx.Error(500, "UpdateAPIAssignee", err)
ctx.Error(500, "UpdateAssignees", err)
return
}
}

View File

@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/notification"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
issue_service "code.gitea.io/gitea/services/issue"
milestone_service "code.gitea.io/gitea/services/milestone"
pull_service "code.gitea.io/gitea/services/pull"
)
@@ -285,8 +286,26 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
}
return
}
// Check if the passed assignees is assignable
for _, aID := range assigneeIDs {
assignee, err := models.GetUserByID(aID)
if err != nil {
ctx.Error(500, "GetUserByID", err)
return
}
if err := pull_service.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch, assigneeIDs); err != nil {
valid, err := models.CanBeAssigned(assignee, repo, true)
if err != nil {
ctx.Error(500, "canBeAssigned", err)
return
}
if !valid {
ctx.Error(422, "canBeAssigned", models.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: repo.Name})
return
}
}
if err := pull_service.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
return
@@ -298,6 +317,11 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
return
}
if err := issue_service.AddAssignees(prIssue, ctx.User, assigneeIDs); err != nil {
ctx.ServerError("AddAssignees", err)
return
}
notification.NotifyNewPullRequest(pr)
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
@@ -387,12 +411,12 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
// Send an empty array ([]) to clear all assignees from the Issue.
if ctx.Repo.CanWrite(models.UnitTypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
err = models.UpdateAPIAssignee(issue, form.Assignee, form.Assignees, ctx.User)
err = issue_service.UpdateAssignees(issue, form.Assignee, form.Assignees, ctx.User)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
} else {
ctx.Error(500, "UpdateAPIAssignee", err)
ctx.Error(500, "UpdateAssignees", err)
}
return
}

View File

@@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/ssh"
"code.gitea.io/gitea/modules/task"
@@ -44,6 +45,7 @@ func NewServices() {
setting.NewServices()
mailer.NewContext()
_ = cache.NewContext()
notification.NewContext()
}
// In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology

View File

@@ -503,21 +503,21 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull b
return nil, nil, 0
}
// Check if the passed assignees actually exists and has write access to the repo
// Check if the passed assignees actually exists and is assignable
for _, aID := range assigneeIDs {
user, err := models.GetUserByID(aID)
assignee, err := models.GetUserByID(aID)
if err != nil {
ctx.ServerError("GetUserByID", err)
return nil, nil, 0
}
perm, err := models.GetUserRepoPermission(repo, user)
valid, err := models.CanBeAssigned(assignee, repo, isPull)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
ctx.ServerError("canBeAssigned", err)
return nil, nil, 0
}
if !perm.CanWriteIssuesOrPulls(isPull) {
ctx.ServerError("CanWriteIssuesOrPulls", fmt.Errorf("No permission for %s", user.Name))
if !valid {
ctx.ServerError("canBeAssigned", models.ErrUserDoesNotHaveAccessToRepo{UserID: aID, RepoName: repo.Name})
return nil, nil, 0
}
}
@@ -574,7 +574,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
Content: form.Content,
Ref: form.Ref,
}
if err := issue_service.NewIssue(repo, issue, labelIDs, assigneeIDs, attachments); err != nil {
if err := issue_service.NewIssue(repo, issue, labelIDs, attachments); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error())
return
@@ -583,6 +583,11 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
return
}
if err := issue_service.AddAssignees(issue, ctx.User, assigneeIDs); err != nil {
log.Error("AddAssignees: %v", err)
ctx.Flash.Error(ctx.Tr("issues.assignee.error"))
}
notification.NotifyNewIssue(issue)
log.Trace("Issue created: %d/%d", repo.ID, issue.ID)
@@ -1112,7 +1117,7 @@ func UpdateIssueMilestone(ctx *context.Context) {
})
}
// UpdateIssueAssignee change issue's assignee
// UpdateIssueAssignee change issue's or pull's assignee
func UpdateIssueAssignee(ctx *context.Context) {
issues := getActionIssues(ctx)
if ctx.Written() {
@@ -1130,10 +1135,29 @@ func UpdateIssueAssignee(ctx *context.Context) {
return
}
default:
if err := issue.ChangeAssignee(ctx.User, assigneeID); err != nil {
ctx.ServerError("ChangeAssignee", err)
assignee, err := models.GetUserByID(assigneeID)
if err != nil {
ctx.ServerError("GetUserByID", err)
return
}
valid, err := models.CanBeAssigned(assignee, issue.Repo, issue.IsPull)
if err != nil {
ctx.ServerError("canBeAssigned", err)
return
}
if !valid {
ctx.ServerError("canBeAssigned", models.ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: issue.Repo.Name})
return
}
removed, comment, err := issue.ToggleAssignee(ctx.User, assigneeID)
if err != nil {
ctx.ServerError("ToggleAssignee", err)
return
}
notification.NotifyIssueChangeAssignee(ctx.User, issue, assignee, removed, comment)
}
}
ctx.JSON(200, map[string]interface{}{

View File

@@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
"github.com/unknwon/com"
@@ -770,7 +771,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
// instead of 500.
if err := pull_service.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch, assigneeIDs); err != nil {
if err := pull_service.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error())
return
@@ -782,6 +783,11 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
return
}
if err := issue_service.AddAssignees(pullIssue, ctx.User, assigneeIDs); err != nil {
log.Error("AddAssignees: %v", err)
ctx.Flash.Error(ctx.Tr("issues.assignee.error"))
}
notification.NotifyNewPullRequest(pullRequest)
log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID)