Skip to content

Commit 263518f

Browse files
committed
Move more issue assignee code from models to issue service
1 parent 70fa80d commit 263518f

File tree

6 files changed

+156
-120
lines changed

6 files changed

+156
-120
lines changed

models/issue_assignees.go

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ package models
77
import (
88
"fmt"
99

10-
"code.gitea.io/gitea/modules/log"
11-
api "code.gitea.io/gitea/modules/structs"
12-
1310
"xorm.io/xorm"
1411
)
1512

@@ -65,31 +62,6 @@ func isUserAssignedToIssue(e Engine, issue *Issue, user *User) (isAssigned bool,
6562
return e.Get(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID})
6663
}
6764

68-
// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array
69-
func DeleteNotPassedAssignee(issue *Issue, doer *User, assignees []*User) (err error) {
70-
var found bool
71-
72-
for _, assignee := range issue.Assignees {
73-
74-
found = false
75-
for _, alreadyAssignee := range assignees {
76-
if assignee.ID == alreadyAssignee.ID {
77-
found = true
78-
break
79-
}
80-
}
81-
82-
if !found {
83-
// This function also does comments and hooks, which is why we call it seperatly instead of directly removing the assignees here
84-
if _, _, err := issue.ToggleAssignee(doer, assignee.ID); err != nil {
85-
return err
86-
}
87-
}
88-
}
89-
90-
return nil
91-
}
92-
9365
// MakeAssigneeList concats a string with all names of the assignees. Useful for logs.
9466
func MakeAssigneeList(issue *Issue) (assigneeList string, err error) {
9567
err = issue.loadAssignees(x)
@@ -131,8 +103,6 @@ func (issue *Issue) ToggleAssignee(doer *User, assigneeID int64) (removed bool,
131103
return false, nil, err
132104
}
133105

134-
go HookQueue.Add(issue.RepoID)
135-
136106
return removed, comment, nil
137107
}
138108

@@ -158,49 +128,6 @@ func (issue *Issue) toggleAssignee(sess *xorm.Session, doer *User, assigneeID in
158128
return removed, comment, err
159129
}
160130

161-
if issue.IsPull {
162-
mode, _ := accessLevelUnit(sess, doer, issue.Repo, UnitTypePullRequests)
163-
164-
if err = issue.loadPullRequest(sess); err != nil {
165-
return false, nil, fmt.Errorf("loadPullRequest: %v", err)
166-
}
167-
issue.PullRequest.Issue = issue
168-
apiPullRequest := &api.PullRequestPayload{
169-
Index: issue.Index,
170-
PullRequest: issue.PullRequest.apiFormat(sess),
171-
Repository: issue.Repo.innerAPIFormat(sess, mode, false),
172-
Sender: doer.APIFormat(),
173-
}
174-
if removed {
175-
apiPullRequest.Action = api.HookIssueUnassigned
176-
} else {
177-
apiPullRequest.Action = api.HookIssueAssigned
178-
}
179-
// Assignee comment triggers a webhook
180-
if err := prepareWebhooks(sess, issue.Repo, HookEventPullRequest, apiPullRequest); err != nil {
181-
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
182-
return false, nil, err
183-
}
184-
} else {
185-
mode, _ := accessLevelUnit(sess, doer, issue.Repo, UnitTypeIssues)
186-
187-
apiIssue := &api.IssuePayload{
188-
Index: issue.Index,
189-
Issue: issue.apiFormat(sess),
190-
Repository: issue.Repo.innerAPIFormat(sess, mode, false),
191-
Sender: doer.APIFormat(),
192-
}
193-
if removed {
194-
apiIssue.Action = api.HookIssueUnassigned
195-
} else {
196-
apiIssue.Action = api.HookIssueAssigned
197-
}
198-
// Assignee comment triggers a webhook
199-
if err := prepareWebhooks(sess, issue.Repo, HookEventIssues, apiIssue); err != nil {
200-
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
201-
return false, nil, err
202-
}
203-
}
204131
return removed, comment, nil
205132
}
206133

models/repo_permission.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@ func AccessLevel(user *User, repo *Repository) (AccessMode, error) {
311311
return accessLevelUnit(x, user, repo, UnitTypeCode)
312312
}
313313

314+
// AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the
315+
// user does not have access.
316+
func AccessLevelUnit(user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
317+
return accessLevelUnit(x, user, repo, unitType)
318+
}
319+
314320
func accessLevelUnit(e Engine, user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
315321
perm, err := getUserRepoPermission(e, repo, user)
316322
if err != nil {

modules/notification/webhook/webhook.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,95 @@ func (m *webhookNotifier) NotifyDeleteRepository(doer *models.User, repo *models
129129
go models.HookQueue.Add(repo.ID)
130130
}
131131
}
132+
133+
func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
134+
if issue.IsPull {
135+
mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypePullRequests)
136+
137+
if err := issue.LoadPullRequest(); err != nil {
138+
log.Error("LoadPullRequest failed: %v", err)
139+
return
140+
}
141+
issue.PullRequest.Issue = issue
142+
apiPullRequest := &api.PullRequestPayload{
143+
Index: issue.Index,
144+
PullRequest: issue.PullRequest.APIFormat(),
145+
Repository: issue.Repo.APIFormat(mode),
146+
Sender: doer.APIFormat(),
147+
}
148+
if removed {
149+
apiPullRequest.Action = api.HookIssueUnassigned
150+
} else {
151+
apiPullRequest.Action = api.HookIssueAssigned
152+
}
153+
// Assignee comment triggers a webhook
154+
if err := models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, apiPullRequest); err != nil {
155+
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
156+
return
157+
}
158+
} else {
159+
mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypeIssues)
160+
161+
apiIssue := &api.IssuePayload{
162+
Index: issue.Index,
163+
Issue: issue.APIFormat(),
164+
Repository: issue.Repo.APIFormat(mode),
165+
Sender: doer.APIFormat(),
166+
}
167+
if removed {
168+
apiIssue.Action = api.HookIssueUnassigned
169+
} else {
170+
apiIssue.Action = api.HookIssueAssigned
171+
}
172+
// Assignee comment triggers a webhook
173+
if err := models.PrepareWebhooks(issue.Repo, models.HookEventIssues, apiIssue); err != nil {
174+
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
175+
return
176+
}
177+
}
178+
179+
go models.HookQueue.Add(issue.RepoID)
180+
}
181+
182+
func (m *webhookNotifier) NotifyIssueChangeTitle(doer *models.User, issue *models.Issue, oldTitle string) {
183+
mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
184+
var err error
185+
if issue.IsPull {
186+
if err = issue.LoadPullRequest(); err != nil {
187+
log.Error("LoadPullRequest failed: %v", err)
188+
return
189+
}
190+
issue.PullRequest.Issue = issue
191+
err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
192+
Action: api.HookIssueEdited,
193+
Index: issue.Index,
194+
Changes: &api.ChangesPayload{
195+
Title: &api.ChangesFromPayload{
196+
From: oldTitle,
197+
},
198+
},
199+
PullRequest: issue.PullRequest.APIFormat(),
200+
Repository: issue.Repo.APIFormat(mode),
201+
Sender: doer.APIFormat(),
202+
})
203+
} else {
204+
err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
205+
Action: api.HookIssueEdited,
206+
Index: issue.Index,
207+
Changes: &api.ChangesPayload{
208+
Title: &api.ChangesFromPayload{
209+
From: oldTitle,
210+
},
211+
},
212+
Issue: issue.APIFormat(),
213+
Repository: issue.Repo.APIFormat(mode),
214+
Sender: issue.Poster.APIFormat(),
215+
})
216+
}
217+
218+
if err != nil {
219+
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
220+
} else {
221+
go models.HookQueue.Add(issue.RepoID)
222+
}
223+
}

routers/repo/issue.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,14 +1050,11 @@ func UpdateIssueTitle(ctx *context.Context) {
10501050
return
10511051
}
10521052

1053-
oldTitle := issue.Title
10541053
if err := issue_service.ChangeTitle(issue, ctx.User, title); err != nil {
10551054
ctx.ServerError("ChangeTitle", err)
10561055
return
10571056
}
10581057

1059-
notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle)
1060-
10611058
ctx.JSON(200, map[string]interface{}{
10621059
"title": issue.Title,
10631060
})
@@ -1130,7 +1127,7 @@ func UpdateIssueAssignee(ctx *context.Context) {
11301127
for _, issue := range issues {
11311128
switch action {
11321129
case "clear":
1133-
if err := models.DeleteNotPassedAssignee(issue, ctx.User, []*models.User{}); err != nil {
1130+
if err := issue_service.DeleteNotPassedAssignee(issue, ctx.User, []*models.User{}); err != nil {
11341131
ctx.ServerError("ClearAssignees", err)
11351132
return
11361133
}
@@ -1151,7 +1148,7 @@ func UpdateIssueAssignee(ctx *context.Context) {
11511148
return
11521149
}
11531150

1154-
removed, comment, err := issue.ToggleAssignee(ctx.User, assigneeID)
1151+
removed, comment, err := issue_service.ToggleAssignee(issue, ctx.User, assigneeID)
11551152
if err != nil {
11561153
ctx.ServerError("ToggleAssignee", err)
11571154
return

services/issue/assignee.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package issue
6+
7+
import (
8+
"code.gitea.io/gitea/models"
9+
"code.gitea.io/gitea/modules/notification"
10+
)
11+
12+
// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array
13+
func DeleteNotPassedAssignee(issue *models.Issue, doer *models.User, assignees []*models.User) (err error) {
14+
var found bool
15+
16+
for _, assignee := range issue.Assignees {
17+
18+
found = false
19+
for _, alreadyAssignee := range assignees {
20+
if assignee.ID == alreadyAssignee.ID {
21+
found = true
22+
break
23+
}
24+
}
25+
26+
if !found {
27+
// This function also does comments and hooks, which is why we call it seperatly instead of directly removing the assignees here
28+
if _, _, err := ToggleAssignee(issue, doer, assignee.ID); err != nil {
29+
return err
30+
}
31+
}
32+
}
33+
34+
return nil
35+
}
36+
37+
// ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it.
38+
func ToggleAssignee(issue *models.Issue, doer *models.User, assigneeID int64) (removed bool, comment *models.Comment, err error) {
39+
removed, comment, err = issue.ToggleAssignee(doer, assigneeID)
40+
if err != nil {
41+
return
42+
}
43+
44+
assignee, err1 := models.GetUserByID(assigneeID)
45+
if err1 != nil {
46+
err = err1
47+
return
48+
}
49+
50+
notification.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
51+
52+
return
53+
}

services/issue/issue.go

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -56,44 +56,7 @@ func ChangeTitle(issue *models.Issue, doer *models.User, title string) (err erro
5656
return
5757
}
5858

59-
mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
60-
if issue.IsPull {
61-
if err = issue.LoadPullRequest(); err != nil {
62-
return fmt.Errorf("loadPullRequest: %v", err)
63-
}
64-
issue.PullRequest.Issue = issue
65-
err = models.PrepareWebhooks(issue.Repo, models.HookEventPullRequest, &api.PullRequestPayload{
66-
Action: api.HookIssueEdited,
67-
Index: issue.Index,
68-
Changes: &api.ChangesPayload{
69-
Title: &api.ChangesFromPayload{
70-
From: oldTitle,
71-
},
72-
},
73-
PullRequest: issue.PullRequest.APIFormat(),
74-
Repository: issue.Repo.APIFormat(mode),
75-
Sender: doer.APIFormat(),
76-
})
77-
} else {
78-
err = models.PrepareWebhooks(issue.Repo, models.HookEventIssues, &api.IssuePayload{
79-
Action: api.HookIssueEdited,
80-
Index: issue.Index,
81-
Changes: &api.ChangesPayload{
82-
Title: &api.ChangesFromPayload{
83-
From: oldTitle,
84-
},
85-
},
86-
Issue: issue.APIFormat(),
87-
Repository: issue.Repo.APIFormat(mode),
88-
Sender: issue.Poster.APIFormat(),
89-
})
90-
}
91-
92-
if err != nil {
93-
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
94-
} else {
95-
go models.HookQueue.Add(issue.RepoID)
96-
}
59+
notification.NotifyIssueChangeTitle(doer, issue, oldTitle)
9760

9861
return nil
9962
}
@@ -134,7 +97,7 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees
13497
}
13598

13699
// Delete all old assignees not passed
137-
if err = models.DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil {
100+
if err = DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil {
138101
return err
139102
}
140103

@@ -179,13 +142,11 @@ func AddAssigneeIfNotAssigned(issue *models.Issue, doer *models.User, assigneeID
179142
return models.ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: issue.Repo.Name}
180143
}
181144

182-
removed, comment, err := issue.ToggleAssignee(doer, assigneeID)
145+
_, _, err = ToggleAssignee(issue, doer, assigneeID)
183146
if err != nil {
184147
return err
185148
}
186149

187-
notification.NotifyIssueChangeAssignee(doer, issue, assignee, removed, comment)
188-
189150
return nil
190151
}
191152

0 commit comments

Comments
 (0)