Skip to content

Commit b9c8d5d

Browse files
tyroneyehcolonelpanic8
authored andcommitted
Support multiple projects
1 parent 481e738 commit b9c8d5d

File tree

13 files changed

+160
-99
lines changed

13 files changed

+160
-99
lines changed

models/issues/issue.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,14 @@ type Issue struct {
102102
PosterID int64 `xorm:"INDEX"`
103103
Poster *user_model.User `xorm:"-"`
104104
OriginalAuthor string
105-
OriginalAuthorID int64 `xorm:"index"`
106-
Title string `xorm:"name"`
107-
Content string `xorm:"LONGTEXT"`
108-
RenderedContent string `xorm:"-"`
109-
Labels []*Label `xorm:"-"`
110-
MilestoneID int64 `xorm:"INDEX"`
111-
Milestone *Milestone `xorm:"-"`
112-
Project *project_model.Project `xorm:"-"`
105+
OriginalAuthorID int64 `xorm:"index"`
106+
Title string `xorm:"name"`
107+
Content string `xorm:"LONGTEXT"`
108+
RenderedContent string `xorm:"-"`
109+
Labels []*Label `xorm:"-"`
110+
MilestoneID int64 `xorm:"INDEX"`
111+
Milestone *Milestone `xorm:"-"`
112+
Projects []*project_model.Project `xorm:"-"`
113113
Priority int
114114
AssigneeID int64 `xorm:"-"`
115115
Assignee *user_model.User `xorm:"-"`

models/issues/issue_list.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,13 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
231231

232232
func (issues IssueList) LoadProjects(ctx context.Context) error {
233233
issueIDs := issues.getIssueIDs()
234-
projectMaps := make(map[int64]*project_model.Project, len(issues))
234+
issueMap := make(map[int64]*Issue, len(issues))
235235
left := len(issueIDs)
236236

237+
for _, issue := range issues {
238+
issueMap[issue.ID] = issue;
239+
}
240+
237241
type projectWithIssueID struct {
238242
*project_model.Project `xorm:"extends"`
239243
IssueID int64
@@ -255,16 +259,14 @@ func (issues IssueList) LoadProjects(ctx context.Context) error {
255259
if err != nil {
256260
return err
257261
}
258-
for _, project := range projects {
259-
projectMaps[project.IssueID] = project.Project
260-
}
261262
left -= limit
262263
issueIDs = issueIDs[limit:]
264+
for _, projectIssue := range projects {
265+
issue := issueMap[projectIssue.IssueID]
266+
issue.Projects = append(issue.Projects, projectIssue.Project)
267+
}
263268
}
264269

265-
for _, issue := range issues {
266-
issue.Project = projectMaps[issue.ID]
267-
}
268270
return nil
269271
}
270272

models/issues/issue_project.go

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,24 @@ import (
1414

1515
// LoadProject load the project the issue was assigned to
1616
func (issue *Issue) LoadProject(ctx context.Context) (err error) {
17-
if issue.Project == nil {
18-
var p project_model.Project
19-
has, err := db.GetEngine(ctx).Table("project").
17+
if issue.Projects == nil {
18+
err = db.GetEngine(ctx).Table("project").
2019
Join("INNER", "project_issue", "project.id=project_issue.project_id").
21-
Where("project_issue.issue_id = ?", issue.ID).Get(&p)
22-
if err != nil {
23-
return err
24-
} else if has {
25-
issue.Project = &p
26-
}
20+
Where("project_issue.issue_id = ?", issue.ID).OrderBy("title").
21+
Find(&issue.Projects)
2722
}
2823
return err
2924
}
3025

31-
func (issue *Issue) projectID(ctx context.Context) int64 {
32-
var ip project_model.ProjectIssue
33-
has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip)
34-
if err != nil || !has {
35-
return 0
26+
27+
func (issue *Issue) projectIDs(ctx context.Context) []int64 {
28+
var ips []int64
29+
if err := db.GetEngine(ctx).Table("project_issue").Select("project_id").
30+
Where("issue_id=?", issue.ID).Find(&ips); err != nil {
31+
return nil
3632
}
37-
return ip.ProjectID
33+
34+
return ips
3835
}
3936

4037
// ProjectBoardID return project board id if issue was assigned to one
@@ -96,57 +93,101 @@ func LoadIssuesFromBoardList(ctx context.Context, bs project_model.BoardList) (m
9693
}
9794

9895
// ChangeProjectAssign changes the project associated with an issue
99-
func ChangeProjectAssign(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
96+
func ChangeProjectAssign(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64, action string) error {
10097
ctx, committer, err := db.TxContext(ctx)
10198
if err != nil {
10299
return err
103100
}
104101
defer committer.Close()
105102

106-
if err := addUpdateIssueProject(ctx, issue, doer, newProjectID); err != nil {
103+
if err := addUpdateIssueProject(ctx, issue, doer, newProjectID, action); err != nil {
107104
return err
108105
}
109106

110107
return committer.Commit()
111108
}
112109

113-
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
114-
oldProjectID := issue.projectID(ctx)
115-
110+
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64, action string) error {
116111
if err := issue.LoadRepo(ctx); err != nil {
117112
return err
118113
}
119114

120-
// Only check if we add a new project and not remove it.
121-
if newProjectID > 0 {
122-
newProject, err := project_model.GetProjectByID(ctx, newProjectID)
123-
if err != nil {
124-
return err
115+
oldProjectIDs := issue.projectIDs(ctx)
116+
117+
if len(oldProjectIDs) > 0 {
118+
for _, i := range oldProjectIDs {
119+
// Only check if we add a new project and not remove it.
120+
if newProjectID > 0 {
121+
newProject, err := project_model.GetProjectByID(ctx, newProjectID)
122+
if err != nil {
123+
return err
124+
}
125+
if newProject.RepoID != issue.RepoID && newProject.OwnerID != issue.Repo.OwnerID {
126+
return fmt.Errorf("issue's repository is not the same as project's repository")
127+
}
128+
}
129+
130+
if action == "attach" && newProjectID > 0 {
131+
if err := db.Insert(ctx, &project_model.ProjectIssue{
132+
IssueID: issue.ID,
133+
ProjectID: newProjectID,
134+
}); err != nil {
135+
return err
136+
}
137+
i = 0
138+
} else {
139+
if action == "clear" {
140+
if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil {
141+
return err
142+
}
143+
} else {
144+
i = newProjectID
145+
newProjectID = 0
146+
if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=? AND project_issue.project_id=?", issue.ID, i).Delete(&project_model.ProjectIssue{}); err != nil {
147+
return err
148+
}
149+
}
150+
}
151+
152+
if i > 0 || newProjectID > 0 {
153+
if _, err := CreateComment(ctx, &CreateCommentOptions{
154+
Type: CommentTypeProject,
155+
Doer: doer,
156+
Repo: issue.Repo,
157+
Issue: issue,
158+
OldProjectID: i,
159+
ProjectID: newProjectID,
160+
}); err != nil {
161+
return err
162+
}
163+
}
164+
if action != "clear" && newProjectID == 0 || newProjectID > 0 {
165+
break
166+
}
125167
}
126-
if newProject.RepoID != issue.RepoID && newProject.OwnerID != issue.Repo.OwnerID {
127-
return fmt.Errorf("issue's repository is not the same as project's repository")
168+
} else {
169+
if action == "attach" || action == "" {
170+
if err := db.Insert(ctx, &project_model.ProjectIssue{
171+
IssueID: issue.ID,
172+
ProjectID: newProjectID,
173+
}); err != nil {
174+
return err
175+
}
128176
}
129-
}
130-
131-
if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil {
132-
return err
133-
}
134177

135-
if oldProjectID > 0 || newProjectID > 0 {
136-
if _, err := CreateComment(ctx, &CreateCommentOptions{
137-
Type: CommentTypeProject,
138-
Doer: doer,
139-
Repo: issue.Repo,
140-
Issue: issue,
141-
OldProjectID: oldProjectID,
142-
ProjectID: newProjectID,
143-
}); err != nil {
144-
return err
178+
if newProjectID > 0 {
179+
if _, err := CreateComment(ctx, &CreateCommentOptions{
180+
Type: CommentTypeProject,
181+
Doer: doer,
182+
Repo: issue.Repo,
183+
Issue: issue,
184+
OldProjectID: 0,
185+
ProjectID: newProjectID,
186+
}); err != nil {
187+
return err
188+
}
145189
}
146190
}
147191

148-
return db.Insert(ctx, &project_model.ProjectIssue{
149-
IssueID: issue.ID,
150-
ProjectID: newProjectID,
151-
})
192+
return nil
152193
}

models/issues/issue_search.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,14 @@ func applyProjectBoardCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.S
184184
// opts.ProjectBoardID == 0 means all project boards,
185185
// do not need to apply any condition
186186
if opts.ProjectBoardID > 0 {
187-
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID}))
188-
} else if opts.ProjectBoardID == db.NoConditionID {
189-
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0}))
187+
sess.In("issue.id", builder.Select("issue_id").From("project_issue").
188+
Where(builder.Eq{"project_board_id": opts.ProjectBoardID}))
189+
} else if opts.ProjectID > 0 {
190+
sess.In("issue.id", builder.Select("issue_id").From("project_issue").
191+
Where(builder.Eq{"project_board_id": 0, "project_id": opts.ProjectID}))
192+
} else {
193+
sess.In("issue.id", builder.Select("issue_id").From("project_issue").
194+
Where(builder.Eq{"project_board_id": 0}))
190195
}
191196
return sess
192197
}

models/project/issue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs
9393
}
9494

9595
for sorting, issueID := range sortedIssueIDs {
96-
_, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=?", board.ID, sorting, issueID)
96+
_, err = sess.Exec("UPDATE `project_issue` SET project_board_id=?, sorting=? WHERE issue_id=? AND project_id=?", board.ID, sorting, issueID, board.ProjectID)
9797
if err != nil {
9898
return err
9999
}

modules/indexer/issues/internal/model.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type IndexerData struct {
2626
LabelIDs []int64 `json:"label_ids"`
2727
NoLabel bool `json:"no_label"` // True if LabelIDs is empty
2828
MilestoneID int64 `json:"milestone_id"`
29-
ProjectID int64 `json:"project_id"`
29+
ProjectIDs []int64 `json:"project_id"`
3030
ProjectBoardID int64 `json:"project_board_id"`
3131
PosterID int64 `json:"poster_id"`
3232
AssigneeID int64 `json:"assignee_id"`

modules/indexer/issues/util.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD
8989
return nil, false, err
9090
}
9191

92-
var projectID int64
93-
if issue.Project != nil {
94-
projectID = issue.Project.ID
92+
var projectIDs []int64
93+
for _, project := range issue.Projects {
94+
projectIDs = append(projectIDs, project.ID)
9595
}
9696

9797
return &internal.IndexerData{
@@ -106,7 +106,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD
106106
LabelIDs: labels,
107107
NoLabel: len(labels) == 0,
108108
MilestoneID: issue.MilestoneID,
109-
ProjectID: projectID,
109+
ProjectIDs: projectIDs,
110110
ProjectBoardID: issue.ProjectBoardID(ctx),
111111
PosterID: issue.PosterID,
112112
AssigneeID: issue.AssigneeID,

routers/web/org/projects.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -461,14 +461,9 @@ func UpdateIssueProject(ctx *context.Context) {
461461
}
462462

463463
projectID := ctx.FormInt64("id")
464+
action := ctx.FormString("action")
464465
for _, issue := range issues {
465-
if issue.Project != nil {
466-
if issue.Project.ID == projectID {
467-
continue
468-
}
469-
}
470-
471-
if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID); err != nil {
466+
if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID, action); err != nil {
472467
ctx.ServerError("ChangeProjectAssign", err)
473468
return
474469
}

routers/web/repo/issue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ func NewIssuePost(ctx *context.Context) {
12441244
ctx.Error(http.StatusBadRequest, "user hasn't permissions to read projects")
12451245
return
12461246
}
1247-
if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID); err != nil {
1247+
if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID, ctx.FormString("action")); err != nil {
12481248
ctx.ServerError("ChangeProjectAssign", err)
12491249
return
12501250
}

routers/web/repo/projects.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -385,14 +385,10 @@ func UpdateIssueProject(ctx *context.Context) {
385385
}
386386

387387
projectID := ctx.FormInt64("id")
388+
action := ctx.FormString("action")
388389
for _, issue := range issues {
389-
if issue.Project != nil {
390-
if issue.Project.ID == projectID {
391-
continue
392-
}
393-
}
394390

395-
if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID); err != nil {
391+
if err := issues_model.ChangeProjectAssign(ctx, issue, ctx.Doer, projectID, action); err != nil {
396392
ctx.ServerError("ChangeProjectAssign", err)
397393
return
398394
}

0 commit comments

Comments
 (0)