issue.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package repo
  2. import (
  3. "net/http"
  4. "strings"
  5. "github.com/cockroachdb/errors"
  6. api "github.com/gogs/go-gogs-client"
  7. "gogs.io/gogs/internal/conf"
  8. "gogs.io/gogs/internal/context"
  9. "gogs.io/gogs/internal/database"
  10. )
  11. func listIssues(c *context.APIContext, opts *database.IssuesOptions) {
  12. issues, err := database.Issues(opts)
  13. if err != nil {
  14. c.Error(err, "list issues")
  15. return
  16. }
  17. count, err := database.IssuesCount(opts)
  18. if err != nil {
  19. c.Error(err, "count issues")
  20. return
  21. }
  22. // FIXME: use IssueList to improve performance.
  23. apiIssues := make([]*api.Issue, len(issues))
  24. for i := range issues {
  25. if err = issues[i].LoadAttributes(); err != nil {
  26. c.Error(err, "load attributes")
  27. return
  28. }
  29. apiIssues[i] = issues[i].APIFormat()
  30. }
  31. c.SetLinkHeader(int(count), conf.UI.IssuePagingNum)
  32. c.JSONSuccess(&apiIssues)
  33. }
  34. func ListUserIssues(c *context.APIContext) {
  35. opts := database.IssuesOptions{
  36. AssigneeID: c.User.ID,
  37. Page: c.QueryInt("page"),
  38. IsClosed: api.StateType(c.Query("state")) == api.STATE_CLOSED,
  39. }
  40. listIssues(c, &opts)
  41. }
  42. func ListIssues(c *context.APIContext) {
  43. opts := database.IssuesOptions{
  44. RepoID: c.Repo.Repository.ID,
  45. Page: c.QueryInt("page"),
  46. IsClosed: api.StateType(c.Query("state")) == api.STATE_CLOSED,
  47. }
  48. listIssues(c, &opts)
  49. }
  50. func GetIssue(c *context.APIContext) {
  51. issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index"))
  52. if err != nil {
  53. c.NotFoundOrError(err, "get issue by index")
  54. return
  55. }
  56. c.JSONSuccess(issue.APIFormat())
  57. }
  58. func CreateIssue(c *context.APIContext, form api.CreateIssueOption) {
  59. issue := &database.Issue{
  60. RepoID: c.Repo.Repository.ID,
  61. Title: form.Title,
  62. PosterID: c.User.ID,
  63. Poster: c.User,
  64. Content: form.Body,
  65. }
  66. if c.Repo.IsWriter() {
  67. if len(form.Assignee) > 0 {
  68. assignee, err := database.Handle.Users().GetByUsername(c.Req.Context(), form.Assignee)
  69. if err != nil {
  70. if database.IsErrUserNotExist(err) {
  71. c.ErrorStatus(http.StatusUnprocessableEntity, errors.Newf("assignee does not exist: [name: %s]", form.Assignee))
  72. } else {
  73. c.Error(err, "get user by name")
  74. }
  75. return
  76. }
  77. issue.AssigneeID = assignee.ID
  78. }
  79. issue.MilestoneID = form.Milestone
  80. } else {
  81. form.Labels = nil
  82. }
  83. if err := database.NewIssue(c.Repo.Repository, issue, form.Labels, nil); err != nil {
  84. c.Error(err, "new issue")
  85. return
  86. }
  87. if form.Closed {
  88. if err := issue.ChangeStatus(c.User, c.Repo.Repository, true); err != nil {
  89. c.Error(err, "change status to closed")
  90. return
  91. }
  92. }
  93. // Refetch from database to assign some automatic values
  94. var err error
  95. issue, err = database.GetIssueByID(issue.ID)
  96. if err != nil {
  97. c.Error(err, "get issue by ID")
  98. return
  99. }
  100. c.JSON(http.StatusCreated, issue.APIFormat())
  101. }
  102. func EditIssue(c *context.APIContext, form api.EditIssueOption) {
  103. issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index"))
  104. if err != nil {
  105. c.NotFoundOrError(err, "get issue by index")
  106. return
  107. }
  108. if !issue.IsPoster(c.User.ID) && !c.Repo.IsWriter() {
  109. c.Status(http.StatusForbidden)
  110. return
  111. }
  112. if len(form.Title) > 0 {
  113. issue.Title = form.Title
  114. }
  115. if form.Body != nil {
  116. issue.Content = *form.Body
  117. }
  118. if c.Repo.IsWriter() && form.Assignee != nil &&
  119. (issue.Assignee == nil || issue.Assignee.LowerName != strings.ToLower(*form.Assignee)) {
  120. if *form.Assignee == "" {
  121. issue.AssigneeID = 0
  122. } else {
  123. assignee, err := database.Handle.Users().GetByUsername(c.Req.Context(), *form.Assignee)
  124. if err != nil {
  125. if database.IsErrUserNotExist(err) {
  126. c.ErrorStatus(http.StatusUnprocessableEntity, errors.Newf("assignee does not exist: [name: %s]", *form.Assignee))
  127. } else {
  128. c.Error(err, "get user by name")
  129. }
  130. return
  131. }
  132. issue.AssigneeID = assignee.ID
  133. }
  134. if err = database.UpdateIssueUserByAssignee(issue); err != nil {
  135. c.Error(err, "update issue user by assignee")
  136. return
  137. }
  138. }
  139. if c.Repo.IsWriter() && form.Milestone != nil &&
  140. issue.MilestoneID != *form.Milestone {
  141. oldMilestoneID := issue.MilestoneID
  142. issue.MilestoneID = *form.Milestone
  143. if err = database.ChangeMilestoneAssign(c.User, issue, oldMilestoneID); err != nil {
  144. c.Error(err, "change milestone assign")
  145. return
  146. }
  147. }
  148. if err = database.UpdateIssue(issue); err != nil {
  149. c.Error(err, "update issue")
  150. return
  151. }
  152. if form.State != nil {
  153. if err = issue.ChangeStatus(c.User, c.Repo.Repository, api.STATE_CLOSED == api.StateType(*form.State)); err != nil {
  154. c.Error(err, "change status")
  155. return
  156. }
  157. }
  158. // Refetch from database to assign some automatic values
  159. issue, err = database.GetIssueByID(issue.ID)
  160. if err != nil {
  161. c.Error(err, "get issue by ID")
  162. return
  163. }
  164. c.JSON(http.StatusCreated, issue.APIFormat())
  165. }