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.

locks.go 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2017 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 lfs
  5. import (
  6. "encoding/json"
  7. "strconv"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/setting"
  11. api "code.gitea.io/sdk/gitea"
  12. "gopkg.in/macaron.v1"
  13. )
  14. func checkRequest(req macaron.Request) int {
  15. if !setting.LFS.StartServer {
  16. return 404
  17. }
  18. if !MetaMatcher(req) || req.Header.Get("Content-Type") != metaMediaType {
  19. return 400
  20. }
  21. return 200
  22. }
  23. func handleLockListOut(ctx *context.Context, lock *models.LFSLock, err error) {
  24. if err != nil {
  25. if models.IsErrLFSLockNotExist(err) {
  26. ctx.JSON(200, api.LFSLockList{
  27. Locks: []*api.LFSLock{},
  28. })
  29. return
  30. }
  31. ctx.JSON(500, api.LFSLockError{
  32. Message: "unable to list locks : " + err.Error(),
  33. })
  34. return
  35. }
  36. if ctx.Repo.Repository.ID != lock.RepoID {
  37. ctx.JSON(200, api.LFSLockList{
  38. Locks: []*api.LFSLock{},
  39. })
  40. return
  41. }
  42. ctx.JSON(200, api.LFSLockList{
  43. Locks: []*api.LFSLock{lock.APIFormat()},
  44. })
  45. }
  46. // GetListLockHandler list locks
  47. func GetListLockHandler(ctx *context.Context) {
  48. status := checkRequest(ctx.Req)
  49. if status != 200 {
  50. writeStatus(ctx, status)
  51. return
  52. }
  53. ctx.Resp.Header().Set("Content-Type", metaMediaType)
  54. err := models.CheckLFSAccessForRepo(ctx.User, ctx.Repo.Repository.ID, "list")
  55. if err != nil {
  56. if models.IsErrLFSLockUnauthorizedAction(err) {
  57. ctx.JSON(403, api.LFSLockError{
  58. Message: "You must have pull access to list locks : " + err.Error(),
  59. })
  60. return
  61. }
  62. ctx.JSON(500, api.LFSLockError{
  63. Message: "unable to list lock : " + err.Error(),
  64. })
  65. return
  66. }
  67. //TODO handle query cursor and limit
  68. id := ctx.Query("id")
  69. if id != "" { //Case where we request a specific id
  70. v, err := strconv.ParseInt(id, 10, 64)
  71. if err != nil {
  72. ctx.JSON(400, api.LFSLockError{
  73. Message: "bad request : " + err.Error(),
  74. })
  75. return
  76. }
  77. lock, err := models.GetLFSLockByID(int64(v))
  78. handleLockListOut(ctx, lock, err)
  79. return
  80. }
  81. path := ctx.Query("path")
  82. if path != "" { //Case where we request a specific id
  83. lock, err := models.GetLFSLock(ctx.Repo.Repository.ID, path)
  84. handleLockListOut(ctx, lock, err)
  85. return
  86. }
  87. //If no query params path or id
  88. lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID)
  89. if err != nil {
  90. ctx.JSON(500, api.LFSLockError{
  91. Message: "unable to list locks : " + err.Error(),
  92. })
  93. return
  94. }
  95. lockListAPI := make([]*api.LFSLock, len(lockList))
  96. for i, l := range lockList {
  97. lockListAPI[i] = l.APIFormat()
  98. }
  99. ctx.JSON(200, api.LFSLockList{
  100. Locks: lockListAPI,
  101. })
  102. }
  103. // PostLockHandler create lock
  104. func PostLockHandler(ctx *context.Context) {
  105. status := checkRequest(ctx.Req)
  106. if status != 200 {
  107. writeStatus(ctx, status)
  108. return
  109. }
  110. ctx.Resp.Header().Set("Content-Type", metaMediaType)
  111. var req api.LFSLockRequest
  112. dec := json.NewDecoder(ctx.Req.Body().ReadCloser())
  113. err := dec.Decode(&req)
  114. if err != nil {
  115. writeStatus(ctx, 400)
  116. return
  117. }
  118. lock, err := models.CreateLFSLock(&models.LFSLock{
  119. RepoID: ctx.Repo.Repository.ID,
  120. Path: req.Path,
  121. Owner: ctx.User,
  122. })
  123. if err != nil {
  124. if models.IsErrLFSLockAlreadyExist(err) {
  125. ctx.JSON(409, api.LFSLockError{
  126. Lock: lock.APIFormat(),
  127. Message: "already created lock",
  128. })
  129. return
  130. }
  131. if models.IsErrLFSLockUnauthorizedAction(err) {
  132. ctx.JSON(403, api.LFSLockError{
  133. Message: "You must have push access to create locks : " + err.Error(),
  134. })
  135. return
  136. }
  137. ctx.JSON(500, api.LFSLockError{
  138. Message: "internal server error : " + err.Error(),
  139. })
  140. return
  141. }
  142. ctx.JSON(201, api.LFSLockResponse{Lock: lock.APIFormat()})
  143. }
  144. // VerifyLockHandler list locks for verification
  145. func VerifyLockHandler(ctx *context.Context) {
  146. status := checkRequest(ctx.Req)
  147. if status != 200 {
  148. writeStatus(ctx, status)
  149. return
  150. }
  151. ctx.Resp.Header().Set("Content-Type", metaMediaType)
  152. err := models.CheckLFSAccessForRepo(ctx.User, ctx.Repo.Repository.ID, "verify")
  153. if err != nil {
  154. if models.IsErrLFSLockUnauthorizedAction(err) {
  155. ctx.JSON(403, api.LFSLockError{
  156. Message: "You must have push access to verify locks : " + err.Error(),
  157. })
  158. return
  159. }
  160. ctx.JSON(500, api.LFSLockError{
  161. Message: "unable to verify lock : " + err.Error(),
  162. })
  163. return
  164. }
  165. //TODO handle body json cursor and limit
  166. lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID)
  167. if err != nil {
  168. ctx.JSON(500, api.LFSLockError{
  169. Message: "unable to list locks : " + err.Error(),
  170. })
  171. return
  172. }
  173. lockOursListAPI := make([]*api.LFSLock, 0, len(lockList))
  174. lockTheirsListAPI := make([]*api.LFSLock, 0, len(lockList))
  175. for _, l := range lockList {
  176. if l.Owner.ID == ctx.User.ID {
  177. lockOursListAPI = append(lockOursListAPI, l.APIFormat())
  178. } else {
  179. lockTheirsListAPI = append(lockTheirsListAPI, l.APIFormat())
  180. }
  181. }
  182. ctx.JSON(200, api.LFSLockListVerify{
  183. Ours: lockOursListAPI,
  184. Theirs: lockTheirsListAPI,
  185. })
  186. }
  187. // UnLockHandler delete locks
  188. func UnLockHandler(ctx *context.Context) {
  189. status := checkRequest(ctx.Req)
  190. if status != 200 {
  191. writeStatus(ctx, status)
  192. return
  193. }
  194. ctx.Resp.Header().Set("Content-Type", metaMediaType)
  195. var req api.LFSLockDeleteRequest
  196. dec := json.NewDecoder(ctx.Req.Body().ReadCloser())
  197. err := dec.Decode(&req)
  198. if err != nil {
  199. writeStatus(ctx, 400)
  200. return
  201. }
  202. lock, err := models.DeleteLFSLockByID(ctx.ParamsInt64("lid"), ctx.User, req.Force)
  203. if err != nil {
  204. if models.IsErrLFSLockUnauthorizedAction(err) {
  205. ctx.JSON(403, api.LFSLockError{
  206. Message: "You must have push access to delete locks : " + err.Error(),
  207. })
  208. return
  209. }
  210. ctx.JSON(500, api.LFSLockError{
  211. Message: "unable to delete lock : " + err.Error(),
  212. })
  213. return
  214. }
  215. ctx.JSON(200, api.LFSLockResponse{Lock: lock.APIFormat()})
  216. }