gitea源码

issue_project.go 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package issues
  4. import (
  5. "context"
  6. "code.gitea.io/gitea/models/db"
  7. project_model "code.gitea.io/gitea/models/project"
  8. user_model "code.gitea.io/gitea/models/user"
  9. "code.gitea.io/gitea/modules/util"
  10. )
  11. // LoadProject load the project the issue was assigned to
  12. func (issue *Issue) LoadProject(ctx context.Context) (err error) {
  13. if issue.Project == nil {
  14. var p project_model.Project
  15. has, err := db.GetEngine(ctx).Table("project").
  16. Join("INNER", "project_issue", "project.id=project_issue.project_id").
  17. Where("project_issue.issue_id = ?", issue.ID).Get(&p)
  18. if err != nil {
  19. return err
  20. } else if has {
  21. issue.Project = &p
  22. }
  23. }
  24. return err
  25. }
  26. func (issue *Issue) projectID(ctx context.Context) int64 {
  27. var ip project_model.ProjectIssue
  28. has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip)
  29. if err != nil || !has {
  30. return 0
  31. }
  32. return ip.ProjectID
  33. }
  34. // ProjectColumnID return project column id if issue was assigned to one
  35. func (issue *Issue) ProjectColumnID(ctx context.Context) (int64, error) {
  36. var ip project_model.ProjectIssue
  37. has, err := db.GetEngine(ctx).Where("issue_id=?", issue.ID).Get(&ip)
  38. if err != nil {
  39. return 0, err
  40. } else if !has {
  41. return 0, nil
  42. }
  43. return ip.ProjectColumnID, nil
  44. }
  45. func LoadProjectIssueColumnMap(ctx context.Context, projectID, defaultColumnID int64) (map[int64]int64, error) {
  46. issues := make([]project_model.ProjectIssue, 0)
  47. if err := db.GetEngine(ctx).Where("project_id=?", projectID).Find(&issues); err != nil {
  48. return nil, err
  49. }
  50. result := make(map[int64]int64, len(issues))
  51. for _, issue := range issues {
  52. if issue.ProjectColumnID == 0 {
  53. issue.ProjectColumnID = defaultColumnID
  54. }
  55. result[issue.IssueID] = issue.ProjectColumnID
  56. }
  57. return result, nil
  58. }
  59. // LoadIssuesFromColumn load issues assigned to this column
  60. func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, opts *IssuesOptions) (IssueList, error) {
  61. issueList, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) {
  62. o.ProjectColumnID = b.ID
  63. o.ProjectID = b.ProjectID
  64. o.SortType = "project-column-sorting"
  65. }))
  66. if err != nil {
  67. return nil, err
  68. }
  69. if b.Default {
  70. issues, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) {
  71. o.ProjectColumnID = db.NoConditionID
  72. o.ProjectID = b.ProjectID
  73. o.SortType = "project-column-sorting"
  74. }))
  75. if err != nil {
  76. return nil, err
  77. }
  78. issueList = append(issueList, issues...)
  79. }
  80. if err := issueList.LoadComments(ctx); err != nil {
  81. return nil, err
  82. }
  83. return issueList, nil
  84. }
  85. // IssueAssignOrRemoveProject changes the project associated with an issue
  86. // If newProjectID is 0, the issue is removed from the project
  87. func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID, newColumnID int64) error {
  88. return db.WithTx(ctx, func(ctx context.Context) error {
  89. oldProjectID := issue.projectID(ctx)
  90. if err := issue.LoadRepo(ctx); err != nil {
  91. return err
  92. }
  93. // Only check if we add a new project and not remove it.
  94. if newProjectID > 0 {
  95. newProject, err := project_model.GetProjectByID(ctx, newProjectID)
  96. if err != nil {
  97. return err
  98. }
  99. if !newProject.CanBeAccessedByOwnerRepo(issue.Repo.OwnerID, issue.Repo) {
  100. return util.NewPermissionDeniedErrorf("issue %d can't be accessed by project %d", issue.ID, newProject.ID)
  101. }
  102. if newColumnID == 0 {
  103. newDefaultColumn, err := newProject.MustDefaultColumn(ctx)
  104. if err != nil {
  105. return err
  106. }
  107. newColumnID = newDefaultColumn.ID
  108. }
  109. }
  110. if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil {
  111. return err
  112. }
  113. if oldProjectID > 0 || newProjectID > 0 {
  114. if _, err := CreateComment(ctx, &CreateCommentOptions{
  115. Type: CommentTypeProject,
  116. Doer: doer,
  117. Repo: issue.Repo,
  118. Issue: issue,
  119. OldProjectID: oldProjectID,
  120. ProjectID: newProjectID,
  121. }); err != nil {
  122. return err
  123. }
  124. }
  125. if newProjectID == 0 {
  126. return nil
  127. }
  128. if newColumnID == 0 {
  129. panic("newColumnID must not be zero") // shouldn't happen
  130. }
  131. res := struct {
  132. MaxSorting int64
  133. IssueCount int64
  134. }{}
  135. if _, err := db.GetEngine(ctx).Select("max(sorting) as max_sorting, count(*) as issue_count").Table("project_issue").
  136. Where("project_id=?", newProjectID).
  137. And("project_board_id=?", newColumnID).
  138. Get(&res); err != nil {
  139. return err
  140. }
  141. newSorting := util.Iif(res.IssueCount > 0, res.MaxSorting+1, 0)
  142. return db.Insert(ctx, &project_model.ProjectIssue{
  143. IssueID: issue.ID,
  144. ProjectID: newProjectID,
  145. ProjectColumnID: newColumnID,
  146. Sorting: newSorting,
  147. })
  148. })
  149. }