You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

332 lines
8.3 KiB

Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
6 years ago
Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
6 years ago
Issue due date (#3794) * Started adding deadline to ui * Implemented basic issue due date managing * Improved UI for due date managing * Added at least write access to the repo in order to modify issue due dates * Ui improvements * Added issue comments creation when adding/modifying/removing a due date * Show due date in issue list * Added api support for issue due dates * Fixed lint suggestions * Added deadline to sdk * Updated css * Added support for adding/modifiying deadlines for pull requests via api * Fixed comments not created when updating or removing a deadline * update sdk (will do properly once go-gitea/go-sdk#103 is merged) * enhanced updateIssueDeadline * Removed unnessecary Issue.DeadlineString * UI improvements * Small improvments to comment creation + ui & validation improvements * Check if an issue is overdue is now a seperate function * Updated go-sdk with govendor as it was merged * Simplified isOverdue method * removed unessecary deadline to 0 set * Update swagger definitions * Added missing return * Added an explanary comment * Improved updateIssueDeadline method so it'll only update `deadline_unix` * Small changes and improvements * no need to explicitly load the issue when updating a deadline, just use whats already there * small optimisations * Added check if a deadline was modified before updating it * Moved comment creating logic into its own function * Code cleanup for creating deadline comment * locale improvement * When modifying a deadline, the old deadline is saved with the comment * small improvments to xorm session handling when updating an issue deadline + style nitpicks * style nitpicks * Moved checking for if the user has write acces to middleware
6 years ago
  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. "strings"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/indexer"
  11. "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/util"
  13. api "code.gitea.io/sdk/gitea"
  14. )
  15. // ListIssues list the issues of a repository
  16. func ListIssues(ctx *context.APIContext) {
  17. // swagger:operation GET /repos/{owner}/{repo}/issues issue issueListIssues
  18. // ---
  19. // summary: List a repository's issues
  20. // produces:
  21. // - application/json
  22. // parameters:
  23. // - name: owner
  24. // in: path
  25. // description: owner of the repo
  26. // type: string
  27. // required: true
  28. // - name: repo
  29. // in: path
  30. // description: name of the repo
  31. // type: string
  32. // required: true
  33. // - name: state
  34. // in: query
  35. // description: whether issue is open or closed
  36. // type: string
  37. // - name: page
  38. // in: query
  39. // description: page number of requested issues
  40. // type: integer
  41. // - name: q
  42. // in: query
  43. // description: search string
  44. // type: string
  45. // responses:
  46. // "200":
  47. // "$ref": "#/responses/IssueList"
  48. var isClosed util.OptionalBool
  49. switch ctx.Query("state") {
  50. case "closed":
  51. isClosed = util.OptionalBoolTrue
  52. case "all":
  53. isClosed = util.OptionalBoolNone
  54. default:
  55. isClosed = util.OptionalBoolFalse
  56. }
  57. var issues []*models.Issue
  58. keyword := strings.Trim(ctx.Query("q"), " ")
  59. if strings.IndexByte(keyword, 0) >= 0 {
  60. keyword = ""
  61. }
  62. var issueIDs []int64
  63. var err error
  64. if len(keyword) > 0 {
  65. issueIDs, err = indexer.SearchIssuesByKeyword(ctx.Repo.Repository.ID, keyword)
  66. }
  67. // Only fetch the issues if we either don't have a keyword or the search returned issues
  68. // This would otherwise return all issues if no issues were found by the search.
  69. if len(keyword) == 0 || len(issueIDs) > 0 {
  70. issues, err = models.Issues(&models.IssuesOptions{
  71. RepoIDs: []int64{ctx.Repo.Repository.ID},
  72. Page: ctx.QueryInt("page"),
  73. PageSize: setting.UI.IssuePagingNum,
  74. IsClosed: isClosed,
  75. IssueIDs: issueIDs,
  76. })
  77. }
  78. if err != nil {
  79. ctx.Error(500, "Issues", err)
  80. return
  81. }
  82. apiIssues := make([]*api.Issue, len(issues))
  83. for i := range issues {
  84. apiIssues[i] = issues[i].APIFormat()
  85. }
  86. ctx.SetLinkHeader(ctx.Repo.Repository.NumIssues, setting.UI.IssuePagingNum)
  87. ctx.JSON(200, &apiIssues)
  88. }
  89. // GetIssue get an issue of a repository
  90. func GetIssue(ctx *context.APIContext) {
  91. // swagger:operation GET /repos/{owner}/{repo}/issues/{index} issue issueGetIssue
  92. // ---
  93. // summary: Get an issue
  94. // produces:
  95. // - application/json
  96. // parameters:
  97. // - name: owner
  98. // in: path
  99. // description: owner of the repo
  100. // type: string
  101. // required: true
  102. // - name: repo
  103. // in: path
  104. // description: name of the repo
  105. // type: string
  106. // required: true
  107. // - name: index
  108. // in: path
  109. // description: index of the issue to get
  110. // type: integer
  111. // required: true
  112. // responses:
  113. // "200":
  114. // "$ref": "#/responses/Issue"
  115. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  116. if err != nil {
  117. if models.IsErrIssueNotExist(err) {
  118. ctx.Status(404)
  119. } else {
  120. ctx.Error(500, "GetIssueByIndex", err)
  121. }
  122. return
  123. }
  124. ctx.JSON(200, issue.APIFormat())
  125. }
  126. // CreateIssue create an issue of a repository
  127. func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
  128. // swagger:operation POST /repos/{owner}/{repo}/issues issue issueCreateIssue
  129. // ---
  130. // summary: Create an issue
  131. // consumes:
  132. // - application/json
  133. // produces:
  134. // - application/json
  135. // parameters:
  136. // - name: owner
  137. // in: path
  138. // description: owner of the repo
  139. // type: string
  140. // required: true
  141. // - name: repo
  142. // in: path
  143. // description: name of the repo
  144. // type: string
  145. // required: true
  146. // - name: body
  147. // in: body
  148. // schema:
  149. // "$ref": "#/definitions/CreateIssueOption"
  150. // responses:
  151. // "201":
  152. // "$ref": "#/responses/Issue"
  153. var deadlineUnix util.TimeStamp
  154. if form.Deadline != nil {
  155. deadlineUnix = util.TimeStamp(form.Deadline.Unix())
  156. }
  157. issue := &models.Issue{
  158. RepoID: ctx.Repo.Repository.ID,
  159. Title: form.Title,
  160. PosterID: ctx.User.ID,
  161. Poster: ctx.User,
  162. Content: form.Body,
  163. DeadlineUnix: deadlineUnix,
  164. }
  165. // Get all assignee IDs
  166. assigneeIDs, err := models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees)
  167. if err != nil {
  168. if models.IsErrUserNotExist(err) {
  169. ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
  170. } else {
  171. ctx.Error(500, "AddAssigneeByName", err)
  172. }
  173. return
  174. }
  175. if err := models.NewIssue(ctx.Repo.Repository, issue, form.Labels, assigneeIDs, nil); err != nil {
  176. if models.IsErrUserDoesNotHaveAccessToRepo(err) {
  177. ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
  178. return
  179. }
  180. ctx.Error(500, "NewIssue", err)
  181. return
  182. }
  183. if form.Closed {
  184. if err := issue.ChangeStatus(ctx.User, ctx.Repo.Repository, true); err != nil {
  185. ctx.Error(500, "ChangeStatus", err)
  186. return
  187. }
  188. }
  189. // Refetch from database to assign some automatic values
  190. issue, err = models.GetIssueByID(issue.ID)
  191. if err != nil {
  192. ctx.Error(500, "GetIssueByID", err)
  193. return
  194. }
  195. ctx.JSON(201, issue.APIFormat())
  196. }
  197. // EditIssue modify an issue of a repository
  198. func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
  199. // swagger:operation PATCH /repos/{owner}/{repo}/issues/{index} issue issueEditIssue
  200. // ---
  201. // summary: Edit an issue
  202. // consumes:
  203. // - application/json
  204. // produces:
  205. // - application/json
  206. // parameters:
  207. // - name: owner
  208. // in: path
  209. // description: owner of the repo
  210. // type: string
  211. // required: true
  212. // - name: repo
  213. // in: path
  214. // description: name of the repo
  215. // type: string
  216. // required: true
  217. // - name: index
  218. // in: path
  219. // description: index of the issue to edit
  220. // type: integer
  221. // required: true
  222. // - name: body
  223. // in: body
  224. // schema:
  225. // "$ref": "#/definitions/EditIssueOption"
  226. // responses:
  227. // "201":
  228. // "$ref": "#/responses/Issue"
  229. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  230. if err != nil {
  231. if models.IsErrIssueNotExist(err) {
  232. ctx.Status(404)
  233. } else {
  234. ctx.Error(500, "GetIssueByIndex", err)
  235. }
  236. return
  237. }
  238. if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.IsWriter() {
  239. ctx.Status(403)
  240. return
  241. }
  242. if len(form.Title) > 0 {
  243. issue.Title = form.Title
  244. }
  245. if form.Body != nil {
  246. issue.Content = *form.Body
  247. }
  248. // Update the deadline
  249. var deadlineUnix util.TimeStamp
  250. if form.Deadline != nil && !form.Deadline.IsZero() {
  251. deadlineUnix = util.TimeStamp(form.Deadline.Unix())
  252. }
  253. if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
  254. ctx.Error(500, "UpdateIssueDeadline", err)
  255. return
  256. }
  257. // Add/delete assignees
  258. // Deleting is done the Github way (quote from their api documentation):
  259. // https://developer.github.com/v3/issues/#edit-an-issue
  260. // "assignees" (array): Logins for Users to assign to this issue.
  261. // Pass one or more user logins to replace the set of assignees on this Issue.
  262. // Send an empty array ([]) to clear all assignees from the Issue.
  263. if ctx.Repo.IsWriter() && (form.Assignees != nil || form.Assignee != nil) {
  264. oneAssignee := ""
  265. if form.Assignee != nil {
  266. oneAssignee = *form.Assignee
  267. }
  268. err = models.UpdateAPIAssignee(issue, oneAssignee, form.Assignees, ctx.User)
  269. if err != nil {
  270. ctx.Error(500, "UpdateAPIAssignee", err)
  271. return
  272. }
  273. }
  274. if ctx.Repo.IsWriter() && form.Milestone != nil &&
  275. issue.MilestoneID != *form.Milestone {
  276. oldMilestoneID := issue.MilestoneID
  277. issue.MilestoneID = *form.Milestone
  278. if err = models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
  279. ctx.Error(500, "ChangeMilestoneAssign", err)
  280. return
  281. }
  282. }
  283. if err = models.UpdateIssue(issue); err != nil {
  284. ctx.Error(500, "UpdateIssue", err)
  285. return
  286. }
  287. if form.State != nil {
  288. if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, api.StateClosed == api.StateType(*form.State)); err != nil {
  289. ctx.Error(500, "ChangeStatus", err)
  290. return
  291. }
  292. }
  293. // Refetch from database to assign some automatic values
  294. issue, err = models.GetIssueByID(issue.ID)
  295. if err != nil {
  296. ctx.Error(500, "GetIssueByID", err)
  297. return
  298. }
  299. ctx.JSON(201, issue.APIFormat())
  300. }