issue.go 4.6 KB

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