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.

issue_stopwatch.go 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2019 The Gitea 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. "errors"
  7. "net/http"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/routers/api/v1/utils"
  11. )
  12. // StartIssueStopwatch creates a stopwatch for the given issue.
  13. func StartIssueStopwatch(ctx *context.APIContext) {
  14. // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/start issue issueStartStopWatch
  15. // ---
  16. // summary: Start stopwatch on an issue.
  17. // consumes:
  18. // - application/json
  19. // produces:
  20. // - application/json
  21. // parameters:
  22. // - name: owner
  23. // in: path
  24. // description: owner of the repo
  25. // type: string
  26. // required: true
  27. // - name: repo
  28. // in: path
  29. // description: name of the repo
  30. // type: string
  31. // required: true
  32. // - name: index
  33. // in: path
  34. // description: index of the issue to create the stopwatch on
  35. // type: integer
  36. // format: int64
  37. // required: true
  38. // responses:
  39. // "201":
  40. // "$ref": "#/responses/empty"
  41. // "403":
  42. // description: Not repo writer, user does not have rights to toggle stopwatch
  43. // "404":
  44. // "$ref": "#/responses/notFound"
  45. // "409":
  46. // description: Cannot start a stopwatch again if it already exists
  47. issue, err := prepareIssueStopwatch(ctx, false)
  48. if err != nil {
  49. return
  50. }
  51. if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil {
  52. ctx.Error(http.StatusInternalServerError, "CreateOrStopIssueStopwatch", err)
  53. return
  54. }
  55. ctx.Status(http.StatusCreated)
  56. }
  57. // StopIssueStopwatch stops a stopwatch for the given issue.
  58. func StopIssueStopwatch(ctx *context.APIContext) {
  59. // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/stop issue issueStopStopWatch
  60. // ---
  61. // summary: Stop an issue's existing stopwatch.
  62. // consumes:
  63. // - application/json
  64. // produces:
  65. // - application/json
  66. // parameters:
  67. // - name: owner
  68. // in: path
  69. // description: owner of the repo
  70. // type: string
  71. // required: true
  72. // - name: repo
  73. // in: path
  74. // description: name of the repo
  75. // type: string
  76. // required: true
  77. // - name: index
  78. // in: path
  79. // description: index of the issue to stop the stopwatch on
  80. // type: integer
  81. // format: int64
  82. // required: true
  83. // responses:
  84. // "201":
  85. // "$ref": "#/responses/empty"
  86. // "403":
  87. // description: Not repo writer, user does not have rights to toggle stopwatch
  88. // "404":
  89. // "$ref": "#/responses/notFound"
  90. // "409":
  91. // description: Cannot stop a non existent stopwatch
  92. issue, err := prepareIssueStopwatch(ctx, true)
  93. if err != nil {
  94. return
  95. }
  96. if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil {
  97. ctx.Error(http.StatusInternalServerError, "CreateOrStopIssueStopwatch", err)
  98. return
  99. }
  100. ctx.Status(http.StatusCreated)
  101. }
  102. // DeleteIssueStopwatch delete a specific stopwatch
  103. func DeleteIssueStopwatch(ctx *context.APIContext) {
  104. // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/stopwatch/delete issue issueDeleteStopWatch
  105. // ---
  106. // summary: Delete an issue's existing stopwatch.
  107. // consumes:
  108. // - application/json
  109. // produces:
  110. // - application/json
  111. // parameters:
  112. // - name: owner
  113. // in: path
  114. // description: owner of the repo
  115. // type: string
  116. // required: true
  117. // - name: repo
  118. // in: path
  119. // description: name of the repo
  120. // type: string
  121. // required: true
  122. // - name: index
  123. // in: path
  124. // description: index of the issue to stop the stopwatch on
  125. // type: integer
  126. // format: int64
  127. // required: true
  128. // responses:
  129. // "204":
  130. // "$ref": "#/responses/empty"
  131. // "403":
  132. // description: Not repo writer, user does not have rights to toggle stopwatch
  133. // "404":
  134. // "$ref": "#/responses/notFound"
  135. // "409":
  136. // description: Cannot cancel a non existent stopwatch
  137. issue, err := prepareIssueStopwatch(ctx, true)
  138. if err != nil {
  139. return
  140. }
  141. if err := models.CancelStopwatch(ctx.User, issue); err != nil {
  142. ctx.Error(http.StatusInternalServerError, "CancelStopwatch", err)
  143. return
  144. }
  145. ctx.Status(http.StatusNoContent)
  146. }
  147. func prepareIssueStopwatch(ctx *context.APIContext, shouldExist bool) (*models.Issue, error) {
  148. issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
  149. if err != nil {
  150. if models.IsErrIssueNotExist(err) {
  151. ctx.NotFound()
  152. } else {
  153. ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
  154. }
  155. return nil, err
  156. }
  157. if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
  158. ctx.Status(http.StatusForbidden)
  159. return nil, errors.New("Unable to write to PRs")
  160. }
  161. if !ctx.Repo.CanUseTimetracker(issue, ctx.User) {
  162. ctx.Status(http.StatusForbidden)
  163. return nil, errors.New("Cannot use time tracker")
  164. }
  165. if models.StopwatchExists(ctx.User.ID, issue.ID) != shouldExist {
  166. if shouldExist {
  167. ctx.Error(http.StatusConflict, "StopwatchExists", "cannot stop/cancel a non existent stopwatch")
  168. err = errors.New("cannot stop/cancel a non existent stopwatch")
  169. } else {
  170. ctx.Error(http.StatusConflict, "StopwatchExists", "cannot start a stopwatch again if it already exists")
  171. err = errors.New("cannot start a stopwatch again if it already exists")
  172. }
  173. return nil, err
  174. }
  175. return issue, nil
  176. }
  177. // GetStopwatches get all stopwatches
  178. func GetStopwatches(ctx *context.APIContext) {
  179. // swagger:operation GET /user/stopwatches user userGetStopWatches
  180. // ---
  181. // summary: Get list of all existing stopwatches
  182. // parameters:
  183. // - name: page
  184. // in: query
  185. // description: page number of results to return (1-based)
  186. // type: integer
  187. // - name: limit
  188. // in: query
  189. // description: page size of results, maximum page size is 50
  190. // type: integer
  191. // consumes:
  192. // - application/json
  193. // produces:
  194. // - application/json
  195. // responses:
  196. // "200":
  197. // "$ref": "#/responses/StopWatchList"
  198. sws, err := models.GetUserStopwatches(ctx.User.ID, utils.GetListOptions(ctx))
  199. if err != nil {
  200. ctx.Error(http.StatusInternalServerError, "GetUserStopwatches", err)
  201. return
  202. }
  203. apiSWs, err := sws.APIFormat()
  204. if err != nil {
  205. ctx.Error(http.StatusInternalServerError, "APIFormat", err)
  206. return
  207. }
  208. ctx.JSON(http.StatusOK, apiSWs)
  209. }