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.4KB

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