diff --git a/models/issue.go b/models/issue.go index 407702f865bc2..2337c05344f2c 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1100,6 +1100,7 @@ type IssuesOptions struct { ExcludedLabelNames []string SortType string IssueIDs []int64 + NotInProjectID int64 // prioritize issues from this repo PriorityRepoID int64 } @@ -1182,7 +1183,6 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id"). And("project_issue.project_id=?", opts.ProjectID).OrderBy("priority") } - if opts.ProjectBoardID != 0 { if opts.ProjectBoardID > 0 { sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID}).OrderBy("priority")) @@ -1191,6 +1191,12 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { } } + if opts.NotInProjectID != 0 { + if opts.NotInProjectID > 0 { + sess.NotIn("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_id": opts.NotInProjectID}).OrderBy("priority")) + } + } + switch opts.IsPull { case util.OptionalBoolTrue: sess.And("issue.is_pull=?", true) diff --git a/models/project.go b/models/project.go index c135184655c5e..a34ccfeab49df 100644 --- a/models/project.go +++ b/models/project.go @@ -48,6 +48,7 @@ type Project struct { IsClosed bool `xorm:"INDEX"` BoardType ProjectBoardType Type ProjectType + Repo *Repository `xorm:"-"` RenderedContent string `xorm:"-"` @@ -320,13 +321,37 @@ func UpdateBoards(boards []ProjectBoard) error { } // Update given issue priority and column -func UpdateBoardIssues(issues []ProjectIssue) error { - for _, issue := range issues { - if _, err := x.ID(issue.ID).Cols("priority", "project_board_id").Update(&issue); err != nil { - log.Info("failed updating cards priorities %s", err) - return err +func UpdateBoardIssues(issues []ProjectIssue) (error, []ProjectIssue) { + var updatedIssues []ProjectIssue + for _, pissue := range issues { + if pissue.ID != 0 { + if _, err := x.ID(pissue.ID).Cols("priority", "project_board_id").Update(&pissue); err != nil { + log.Info("failed updating cards priorities %s", err) + return err, updatedIssues + } else { + updatedIssues = append(updatedIssues, pissue) + } + } else { + if _, err := x.Insert(&pissue); err != nil { + log.Info("failed inserting cards priorities %s", err) + return err, updatedIssues + } else { + updatedIssues = append(updatedIssues, pissue) + } } + } + return nil, updatedIssues +} +func (p *Project) LoadRepository() error { + var repo = Repository{} + if p.Type == ProjectTypeRepository { + _, err := x.ID(p.RepoID).Get(&repo) + p.Repo = &repo + if err != nil { + log.Info("failed getting repo %w", err) + } + return err } return nil } diff --git a/models/project_issue.go b/models/project_issue.go index 4c88e111f8b39..5fd7a4cc9c55e 100644 --- a/models/project_issue.go +++ b/models/project_issue.go @@ -7,6 +7,7 @@ package models import ( "fmt" + "code.gitea.io/gitea/modules/log" "xorm.io/xorm" ) @@ -143,10 +144,9 @@ func ChangeProjectAssign(issue *Issue, doer *User, newProjectID int64) error { } func addUpdateIssueProject(e *xorm.Session, issue *Issue, doer *User, newProjectID int64) error { - oldProjectID := issue.projectID(e) - if _, err := e.Where("project_issue.issue_id=?", issue.ID).Delete(&ProjectIssue{}); err != nil { + log.Info("failed deleting project issue %w", err) return err } @@ -167,11 +167,21 @@ func addUpdateIssueProject(e *xorm.Session, issue *Issue, doer *User, newProject } } - _, err := e.Insert(&ProjectIssue{ - IssueID: issue.ID, - ProjectID: newProjectID, - }) - return err + var projectIssues []ProjectIssue + if newProjectID != 0 { + err := e.Where("issue_id = ? and project_id = ?", issue.ID, newProjectID).Find(&projectIssues) + if err != nil { + return err + } + if len(projectIssues) == 0 { + _, err := e.Insert(&ProjectIssue{ + IssueID: issue.ID, + ProjectID: newProjectID, + }) + return err + } + } + return nil } // ____ _ _ ____ _ diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index b1447f310867f..300a4ab1a3c53 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -56,6 +56,7 @@ new_fork = New Repository Fork new_org = New Organization new_project = New Project new_project_board = New Project board +add_project_issue = Add Issue manage_org = Manage Organizations admin_panel = Site Administration account_settings = Account Settings diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 0dbf2741ad4bd..fdec75b21b0bd 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -51,6 +51,11 @@ func SearchIssues(ctx *context.APIContext) { // description: repository to prioritize in the results // type: integer // format: int64 + // - name: not_in_project_id + // in: query + // description: project to exclude from search when searching issues to add to a project + // type: integer + // format: int64 // - name: type // in: query // description: filter by type (issues / pulls) if set @@ -158,6 +163,7 @@ func SearchIssues(ctx *context.APIContext) { SortType: "priorityrepo", PriorityRepoID: ctx.QueryInt64("priority_repo_id"), IsPull: isPull, + NotInProjectID: ctx.QueryInt64("not_in_project_id"), } if issues, err = models.Issues(issuesOpt); err != nil { @@ -314,13 +320,14 @@ func ListIssues(ctx *context.APIContext) { // This would otherwise return all issues if no issues were found by the search. if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 { issuesOpt := &models.IssuesOptions{ - ListOptions: listOptions, - RepoIDs: []int64{ctx.Repo.Repository.ID}, - IsClosed: isClosed, - IssueIDs: issueIDs, - LabelIDs: labelIDs, - MilestoneIDs: mileIDs, - IsPull: isPull, + ListOptions: listOptions, + RepoIDs: []int64{ctx.Repo.Repository.ID}, + IsClosed: isClosed, + IssueIDs: issueIDs, + LabelIDs: labelIDs, + MilestoneIDs: mileIDs, + IsPull: isPull, + NotInProjectID: ctx.QueryInt64("not_in_project_id"), } if issues, err = models.Issues(issuesOpt); err != nil { diff --git a/routers/repo/projects.go b/routers/repo/projects.go index 5297a0cf1ebb0..3c75f387e5ab6 100644 --- a/routers/repo/projects.go +++ b/routers/repo/projects.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -265,6 +266,7 @@ func ViewProject(ctx *context.Context) { } return } + if project.RepoID != ctx.Repo.Repository.ID { ctx.NotFound("", nil) return @@ -298,7 +300,10 @@ func ViewProject(ctx *context.Context) { ctx.Data["Boards"] = allBoards ctx.Data["PageIsProjects"] = true ctx.Data["RequiresDraggable"] = true - + project.LoadRepository() + if project.Repo != nil && project.Repo.ID != 0 { + ctx.Data["Repo"] = project.Repo + } ctx.HTML(200, tplProjectsView) } @@ -624,8 +629,10 @@ func UpdateBoardIssuePriority(ctx *context.Context, form auth.UpdateIssuePriorit return } - issues := form - models.UpdateBoardIssues(form.Issues) + err, issues := models.UpdateBoardIssues(form.Issues) + if err != nil { + log.Info("failed updating issues %v", err) + } ctx.JSON(200, issues) } diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 046e0abf24c79..93f7565fd1cdb 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -1,7 +1,7 @@