]> source.dussan.org Git - gitea.git/commitdiff
Move more issue assignee code from models to issue service (#8690)
authorLunny Xiao <xiaolunwen@gmail.com>
Mon, 28 Oct 2019 02:11:50 +0000 (10:11 +0800)
committerGitHub <noreply@github.com>
Mon, 28 Oct 2019 02:11:50 +0000 (10:11 +0800)
* Move more issue assignee code from models to issue service

* fix test

models/issue_assignees.go
models/issue_assignees_test.go
models/repo_permission.go
modules/notification/webhook/webhook.go
routers/repo/issue.go
services/issue/assignee.go [new file with mode: 0644]
services/issue/assignee_test.go [new file with mode: 0644]
services/issue/issue.go

index ed0576b38b071794c5f58440464ae828e35825f6..e15b718eb2afc58c0c7ffae23129ad48864337ef 100644 (file)
@@ -7,9 +7,6 @@ package models
 import (
        "fmt"
 
-       "code.gitea.io/gitea/modules/log"
-       api "code.gitea.io/gitea/modules/structs"
-
        "xorm.io/xorm"
 )
 
@@ -65,31 +62,6 @@ func isUserAssignedToIssue(e Engine, issue *Issue, user *User) (isAssigned bool,
        return e.Get(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID})
 }
 
-// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array
-func DeleteNotPassedAssignee(issue *Issue, doer *User, assignees []*User) (err error) {
-       var found bool
-
-       for _, assignee := range issue.Assignees {
-
-               found = false
-               for _, alreadyAssignee := range assignees {
-                       if assignee.ID == alreadyAssignee.ID {
-                               found = true
-                               break
-                       }
-               }
-
-               if !found {
-                       // This function also does comments and hooks, which is why we call it seperatly instead of directly removing the assignees here
-                       if _, _, err := issue.ToggleAssignee(doer, assignee.ID); err != nil {
-                               return err
-                       }
-               }
-       }
-
-       return nil
-}
-
 // MakeAssigneeList concats a string with all names of the assignees. Useful for logs.
 func MakeAssigneeList(issue *Issue) (assigneeList string, err error) {
        err = issue.loadAssignees(x)
@@ -131,8 +103,6 @@ func (issue *Issue) ToggleAssignee(doer *User, assigneeID int64) (removed bool,
                return false, nil, err
        }
 
-       go HookQueue.Add(issue.RepoID)
-
        return removed, comment, nil
 }
 
@@ -158,49 +128,6 @@ func (issue *Issue) toggleAssignee(sess *xorm.Session, doer *User, assigneeID in
                return removed, comment, err
        }
 
-       if issue.IsPull {
-               mode, _ := accessLevelUnit(sess, doer, issue.Repo, UnitTypePullRequests)
-
-               if err = issue.loadPullRequest(sess); err != nil {
-                       return false, nil, fmt.Errorf("loadPullRequest: %v", err)
-               }
-               issue.PullRequest.Issue = issue
-               apiPullRequest := &api.PullRequestPayload{
-                       Index:       issue.Index,
-                       PullRequest: issue.PullRequest.apiFormat(sess),
-                       Repository:  issue.Repo.innerAPIFormat(sess, mode, false),
-                       Sender:      doer.APIFormat(),
-               }
-               if removed {
-                       apiPullRequest.Action = api.HookIssueUnassigned
-               } else {
-                       apiPullRequest.Action = api.HookIssueAssigned
-               }
-               // Assignee comment triggers a webhook
-               if err := prepareWebhooks(sess, issue.Repo, HookEventPullRequest, apiPullRequest); err != nil {
-                       log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
-                       return false, nil, err
-               }
-       } else {
-               mode, _ := accessLevelUnit(sess, doer, issue.Repo, UnitTypeIssues)
-
-               apiIssue := &api.IssuePayload{
-                       Index:      issue.Index,
-                       Issue:      issue.apiFormat(sess),
-                       Repository: issue.Repo.innerAPIFormat(sess, mode, false),
-                       Sender:     doer.APIFormat(),
-               }
-               if removed {
-                       apiIssue.Action = api.HookIssueUnassigned
-               } else {
-                       apiIssue.Action = api.HookIssueAssigned
-               }
-               // Assignee comment triggers a webhook
-               if err := prepareWebhooks(sess, issue.Repo, HookEventIssues, apiIssue); err != nil {
-                       log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
-                       return false, nil, err
-               }
-       }
        return removed, comment, nil
 }
 
index 1c5b5e7a22f40159a4fab552a8789e42f088ed68..163234b16779350c9d842b16aefaa57955be0086 100644 (file)
@@ -58,13 +58,4 @@ func TestUpdateAssignee(t *testing.T) {
        isAssigned, err = IsUserAssignedToIssue(issue, &User{ID: 4})
        assert.NoError(t, err)
        assert.False(t, isAssigned)
-
-       // Clean everyone
-       err = DeleteNotPassedAssignee(issue, user1, []*User{})
-       assert.NoError(t, err)
-
-       // Check they're gone
-       assignees, err = GetAssigneesByIssue(issue)
-       assert.NoError(t, err)
-       assert.Equal(t, 0, len(assignees))
 }
index fad29bd16959845f43e41b3de735bc2dd349752e..782b195629c928225e33a6b36a4632880f7fa148 100644 (file)
@@ -311,6 +311,12 @@ func AccessLevel(user *User, repo *Repository) (AccessMode, error) {
        return accessLevelUnit(x, user, repo, UnitTypeCode)
 }
 
+// AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the
+// user does not have access.
+func AccessLevelUnit(user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
+       return accessLevelUnit(x, user, repo, unitType)
+}
+
 func accessLevelUnit(e Engine, user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
        perm, err := getUserRepoPermission(e, repo, user)
        if err != nil {
index 13f2f4486a54a5166da9f80fe8a960397606aba2..704b42ec8dbd6057827f9f566c072f413af4e620 100644 (file)
@@ -129,3 +129,95 @@ func (m *webhookNotifier) NotifyDeleteRepository(doer *models.User, repo *models
                go models.HookQueue.Add(repo.ID)
        }
 }
+
+func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
+       if issue.IsPull {
+               mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypePullRequests)
+
+               if err := issue.LoadPullRequest(); err != nil {
+                       log.Error("LoadPullRequest failed: %v", err)
+                       return
+               }
+               issue.PullRequest.Issue = issue
+               apiPullRequest := &api.PullRequestPayload{
+                       Index:       issue.Index,
+                       PullRequest: issue.PullRequest.APIFormat(),
+                       Repository:  issue.Repo.APIFormat(mode),
+                       Sender:      doer.APIFormat(),
+               }
+               if removed {
+                       apiPullRequest.Action = api.HookIssueUnassigned
+               } else {
+                       apiPullRequest.Action = api.HookIssueAssigned
+               }
+               // Assignee comment triggers a webhook
+               if err := models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, apiPullRequest); err != nil {
+                       log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
+                       return
+               }
+       } else {
+               mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypeIssues)
+
+               apiIssue := &api.IssuePayload{
+                       Index:      issue.Index,
+                       Issue:      issue.APIFormat(),
+                       Repository: issue.Repo.APIFormat(mode),
+                       Sender:     doer.APIFormat(),
+               }
+               if removed {
+                       apiIssue.Action = api.HookIssueUnassigned
+               } else {
+                       apiIssue.Action = api.HookIssueAssigned
+               }
+               // Assignee comment triggers a webhook
+               if err := models.PrepareWebhooks(issue.Repo, models.HookEventIssues, apiIssue); err != nil {
+                       log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
+                       return
+               }
+       }
+
+       go models.HookQueue.Add(issue.RepoID)
+}
+
+func (m *webhookNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
+       mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
+       var err error
+       if issue.IsPull {
+               if err = issue.LoadPullRequest(); err != nil {
+                       log.Error("LoadPullRequest failed: %v", err)
+                       return
+               }
+               issue.PullRequest.Issue = issue
+               err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
+                       Action: api.HookIssueEdited,
+                       Index:  issue.Index,
+                       Changes: &api.ChangesPayload{
+                               Title: &api.ChangesFromPayload{
+                                       From: oldTitle,
+                               },
+                       },
+                       PullRequest: issue.PullRequest.APIFormat(),
+                       Repository:  issue.Repo.APIFormat(mode),
+                       Sender:      doer.APIFormat(),
+               })
+       } else {
+               err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
+                       Action: api.HookIssueEdited,
+                       Index:  issue.Index,
+                       Changes: &api.ChangesPayload{
+                               Title: &api.ChangesFromPayload{
+                                       From: oldTitle,
+                               },
+                       },
+                       Issue:      issue.APIFormat(),
+                       Repository: issue.Repo.APIFormat(mode),
+                       Sender:     issue.Poster.APIFormat(),
+               })
+       }
+
+       if err != nil {
+               log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+       } else {
+               go models.HookQueue.Add(issue.RepoID)
+       }
+}
index 94c39ae2240ec8c4e5e6955e63fac3a073d376e9..4e755b7191752a7224331ede66d5f93963060b1c 100644 (file)
@@ -1050,14 +1050,11 @@ func UpdateIssueTitle(ctx *context.Context) {
                return
        }
 
-       oldTitle := issue.Title
        if err := issue_service.ChangeTitle(issue, ctx.User, title); err != nil {
                ctx.ServerError("ChangeTitle", err)
                return
        }
 
-       notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle)
-
        ctx.JSON(200, map[string]interface{}{
                "title": issue.Title,
        })
@@ -1130,7 +1127,7 @@ func UpdateIssueAssignee(ctx *context.Context) {
        for _, issue := range issues {
                switch action {
                case "clear":
-                       if err := models.DeleteNotPassedAssignee(issue, ctx.User, []*models.User{}); err != nil {
+                       if err := issue_service.DeleteNotPassedAssignee(issue, ctx.User, []*models.User{}); err != nil {
                                ctx.ServerError("ClearAssignees", err)
                                return
                        }
@@ -1151,7 +1148,7 @@ func UpdateIssueAssignee(ctx *context.Context) {
                                return
                        }
 
-                       removed, comment, err := issue.ToggleAssignee(ctx.User, assigneeID)
+                       removed, comment, err := issue_service.ToggleAssignee(issue, ctx.User, assigneeID)
                        if err != nil {
                                ctx.ServerError("ToggleAssignee", err)
                                return
diff --git a/services/issue/assignee.go b/services/issue/assignee.go
new file mode 100644 (file)
index 0000000..281f824
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2019 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 issue
+
+import (
+       "code.gitea.io/gitea/models"
+       "code.gitea.io/gitea/modules/notification"
+)
+
+// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array
+func DeleteNotPassedAssignee(issue *models.Issue, doer *models.User, assignees []*models.User) (err error) {
+       var found bool
+
+       for _, assignee := range issue.Assignees {
+
+               found = false
+               for _, alreadyAssignee := range assignees {
+                       if assignee.ID == alreadyAssignee.ID {
+                               found = true
+                               break
+                       }
+               }
+
+               if !found {
+                       // This function also does comments and hooks, which is why we call it seperatly instead of directly removing the assignees here
+                       if _, _, err := ToggleAssignee(issue, doer, assignee.ID); err != nil {
+                               return err
+                       }
+               }
+       }
+
+       return nil
+}
+
+// ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it.
+func ToggleAssignee(issue *models.Issue, doer *models.User, assigneeID int64) (removed bool, comment *models.Comment, err error) {
+       removed, comment, err = issue.ToggleAssignee(doer, assigneeID)
+       if err != nil {
+               return
+       }
+
+       assignee, err1 := models.GetUserByID(assigneeID)
+       if err1 != nil {
+               err = err1
+               return
+       }
+
+       notification.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
+
+       return
+}
diff --git a/services/issue/assignee_test.go b/services/issue/assignee_test.go
new file mode 100644 (file)
index 0000000..bdd2009
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2019 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 issue
+
+import (
+       "testing"
+
+       "code.gitea.io/gitea/models"
+       "github.com/stretchr/testify/assert"
+)
+
+func TestDeleteNotPassedAssignee(t *testing.T) {
+       assert.NoError(t, models.PrepareTestDatabase())
+
+       // Fake issue with assignees
+       issue, err := models.GetIssueWithAttrsByID(1)
+       assert.NoError(t, err)
+
+       user1, err := models.GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running  UpdateAssignee should unassign him
+       assert.NoError(t, err)
+
+       // Check if he got removed
+       isAssigned, err := models.IsUserAssignedToIssue(issue, user1)
+       assert.NoError(t, err)
+       assert.True(t, isAssigned)
+
+       // Clean everyone
+       err = DeleteNotPassedAssignee(issue, user1, []*models.User{})
+       assert.NoError(t, err)
+
+       // Check they're gone
+       assignees, err := models.GetAssigneesByIssue(issue)
+       assert.NoError(t, err)
+       assert.Equal(t, 0, len(assignees))
+}
index a5f725ab70258f5f0106f2c7be9b805203f3dcc6..06472d86508ff1385d89ab1790956418b3f1d115 100644 (file)
@@ -56,44 +56,7 @@ func ChangeTitle(issue *models.Issue, doer *models.User, title string) (err erro
                return
        }
 
-       mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
-       if issue.IsPull {
-               if err = issue.LoadPullRequest(); err != nil {
-                       return fmt.Errorf("loadPullRequest: %v", err)
-               }
-               issue.PullRequest.Issue = issue
-               err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
-                       Action: api.HookIssueEdited,
-                       Index:  issue.Index,
-                       Changes: &api.ChangesPayload{
-                               Title: &api.ChangesFromPayload{
-                                       From: oldTitle,
-                               },
-                       },
-                       PullRequest: issue.PullRequest.APIFormat(),
-                       Repository:  issue.Repo.APIFormat(mode),
-                       Sender:      doer.APIFormat(),
-               })
-       } else {
-               err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
-                       Action: api.HookIssueEdited,
-                       Index:  issue.Index,
-                       Changes: &api.ChangesPayload{
-                               Title: &api.ChangesFromPayload{
-                                       From: oldTitle,
-                               },
-                       },
-                       Issue:      issue.APIFormat(),
-                       Repository: issue.Repo.APIFormat(mode),
-                       Sender:     issue.Poster.APIFormat(),
-               })
-       }
-
-       if err != nil {
-               log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
-       } else {
-               go models.HookQueue.Add(issue.RepoID)
-       }
+       notification.NotifyIssueChangeTitle(doer, issue, oldTitle)
 
        return nil
 }
@@ -134,7 +97,7 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees
        }
 
        // Delete all old assignees not passed
-       if err = models.DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil {
+       if err = DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil {
                return err
        }
 
@@ -179,13 +142,11 @@ func AddAssigneeIfNotAssigned(issue *models.Issue, doer *models.User, assigneeID
                return models.ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: issue.Repo.Name}
        }
 
-       removed, comment, err := issue.ToggleAssignee(doer, assigneeID)
+       _, _, err = ToggleAssignee(issue, doer, assigneeID)
        if err != nil {
                return err
        }
 
-       notification.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
-
        return nil
 }