Skip to content

Commit 8229cd9

Browse files
committed
Add support multiple projects
1 parent 0d5abe3 commit 8229cd9

File tree

20 files changed

+135
-87
lines changed

20 files changed

+135
-87
lines changed

models/db/search.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC"
3131
SearchOrderByForks SearchOrderBy = "num_forks ASC"
3232
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
33+
SearchOrderByTitle SearchOrderBy = "title ASC"
3334
)
3435

3536
const (

models/issues/issue.go

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

models/issues/issue_list.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,19 @@ func (issues IssueList) LoadProjects(ctx context.Context) error {
256256
return err
257257
}
258258
for _, project := range projects {
259-
projectMaps[project.IssueID] = project.Project
259+
projectMaps[project.ID] = project.Project
260260
}
261261
left -= limit
262262
issueIDs = issueIDs[limit:]
263263
}
264264

265265
for _, issue := range issues {
266-
issue.Project = projectMaps[issue.ID]
266+
projectIDs := issue.projectIDs(ctx)
267+
for _, i := range projectIDs {
268+
if projectMaps[i] != nil {
269+
issue.Projects = append(issue.Projects, projectMaps[i])
270+
}
271+
}
267272
}
268273
return nil
269274
}

models/issues/issue_list_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ func TestIssueList_LoadAttributes(t *testing.T) {
6666
}
6767
if issue.ID == int64(1) {
6868
assert.Equal(t, int64(400), issue.TotalTrackedTime)
69-
assert.NotNil(t, issue.Project)
70-
assert.Equal(t, int64(1), issue.Project.ID)
69+
assert.NotNil(t, issue.Projects)
70+
assert.Equal(t, int64(1), issue.Projects[0].ID)
7171
} else {
72-
assert.Nil(t, issue.Project)
72+
assert.Nil(t, issue.Projects)
7373
}
7474
}
7575
}

models/issues/issue_project.go

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,20 @@ 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).Find(&issue.Projects)
2721
}
2822
return err
2923
}
3024

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
25+
func (issue *Issue) projectIDs(ctx context.Context) []int64 {
26+
var ips []int64
27+
if err := db.GetEngine(ctx).Table("project_issue").Select("project_id").Where("issue_id=?", issue.ID).Find(&ips); err != nil {
28+
return nil
3629
}
37-
return ip.ProjectID
30+
return ips
3831
}
3932

4033
// ProjectBoardID return project board id if issue was assigned to one
@@ -91,24 +84,25 @@ func LoadIssuesFromBoardList(ctx context.Context, bs project_model.BoardList) (m
9184
}
9285

9386
// ChangeProjectAssign changes the project associated with an issue
94-
func ChangeProjectAssign(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
87+
func ChangeProjectAssign(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64, action string) error {
9588
ctx, committer, err := db.TxContext(ctx)
9689
if err != nil {
9790
return err
9891
}
9992
defer committer.Close()
10093

101-
if err := addUpdateIssueProject(ctx, issue, doer, newProjectID); err != nil {
94+
if err := addUpdateIssueProject(ctx, issue, doer, newProjectID, action); err != nil {
10295
return err
10396
}
10497

10598
return committer.Commit()
10699
}
107100

108-
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
109-
oldProjectID := issue.projectID(ctx)
101+
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64, action string) error {
102+
var oldProjectIDs []int64
103+
var err error
110104

111-
if err := issue.LoadRepo(ctx); err != nil {
105+
if err = issue.LoadRepo(ctx); err != nil {
112106
return err
113107
}
114108

@@ -123,25 +117,51 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U
123117
}
124118
}
125119

126-
if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil {
127-
return err
120+
if action == "null" {
121+
if newProjectID == 0 {
122+
action = "clear"
123+
} else {
124+
action = "attach"
125+
count, err := db.GetEngine(ctx).Table("project_issue").Where("issue_id=? AND project_id=?", issue.ID, newProjectID).Count()
126+
if err != nil {
127+
return err
128+
}
129+
if count > 0 {
130+
action = "detach"
131+
}
132+
}
133+
}
134+
135+
if action == "attach" {
136+
err = db.Insert(ctx, &project_model.ProjectIssue{
137+
IssueID: issue.ID,
138+
ProjectID: newProjectID,
139+
})
140+
oldProjectIDs = append(oldProjectIDs, 0)
141+
} else if action == "detach" {
142+
_, err = db.GetEngine(ctx).Where("issue_id=? AND project_id=?", issue.ID, newProjectID).Delete(&project_model.ProjectIssue{})
143+
oldProjectIDs = append(oldProjectIDs, newProjectID)
144+
newProjectID = 0
145+
} else if action == "clear" {
146+
if err = db.GetEngine(ctx).Table("project_issue").Select("project_id").Where("issue_id=?", issue.ID).Find(&oldProjectIDs); err != nil {
147+
return err
148+
}
149+
_, err = db.GetEngine(ctx).Where("issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{})
150+
newProjectID = 0
128151
}
129152

130-
if oldProjectID > 0 || newProjectID > 0 {
153+
for i := range oldProjectIDs {
131154
if _, err := CreateComment(ctx, &CreateCommentOptions{
132155
Type: CommentTypeProject,
133156
Doer: doer,
134157
Repo: issue.Repo,
135158
Issue: issue,
136-
OldProjectID: oldProjectID,
159+
OldProjectID: oldProjectIDs[i],
137160
ProjectID: newProjectID,
138161
}); err != nil {
139162
return err
140163
}
141164
}
142165

143-
return db.Insert(ctx, &project_model.ProjectIssue{
144-
IssueID: issue.ID,
145-
ProjectID: newProjectID,
146-
})
166+
return err
147167
}

models/issues/issue_search.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ func applyProjectBoardCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.S
174174
// do not need to apply any condition
175175
if opts.ProjectBoardID > 0 {
176176
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID}))
177+
} else if opts.ProjectID > 0 {
178+
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0, "project_id": opts.ProjectID}))
177179
} else if opts.ProjectBoardID == db.NoConditionID {
178180
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0}))
179181
}

models/issues/issue_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,10 @@ func TestIssueLoadAttributes(t *testing.T) {
418418
}
419419
if issue.ID == int64(1) {
420420
assert.Equal(t, int64(400), issue.TotalTrackedTime)
421-
assert.NotNil(t, issue.Project)
422-
assert.Equal(t, int64(1), issue.Project.ID)
421+
assert.NotNil(t, issue.Projects)
422+
assert.Equal(t, int64(1), issue.Projects[0].ID)
423423
} else {
424-
assert.Nil(t, issue.Project)
424+
assert.Nil(t, issue.Projects)
425425
}
426426
}
427427
}

models/project/issue.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (p *Project) NumOpenIssues(ctx context.Context) int {
7676
}
7777

7878
// MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column
79-
func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64) error {
79+
func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64, projectID int64) error {
8080
return db.WithTx(ctx, func(ctx context.Context) error {
8181
sess := db.GetEngine(ctx)
8282

@@ -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, projectID)
9797
if err != nil {
9898
return err
9999
}

models/project/project.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy {
237237
return db.SearchOrderByRecentUpdated
238238
case "leastupdate":
239239
return db.SearchOrderByLeastUpdated
240+
case "title":
241+
return db.SearchOrderByTitle
240242
default:
241243
return db.SearchOrderByNewest
242244
}

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_ids"`
3030
ProjectBoardID int64 `json:"project_board_id"`
3131
PosterID int64 `json:"poster_id"`
3232
AssigneeID int64 `json:"assignee_id"`

0 commit comments

Comments
 (0)