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

repo.go 8.7 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright 2014 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. "strings"
  7. api "code.gitea.io/sdk/gitea"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/auth"
  10. "code.gitea.io/gitea/modules/context"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/setting"
  13. "code.gitea.io/gitea/routers/api/v1/convert"
  14. )
  15. // Search repositories via options
  16. func Search(ctx *context.APIContext) {
  17. // swagger:route GET /repos/search repoSearch
  18. //
  19. // Produces:
  20. // - application/json
  21. //
  22. // Responses:
  23. // 200: SearchResults
  24. // 500: SearchError
  25. opts := &models.SearchRepoOptions{
  26. Keyword: strings.Trim(ctx.Query("q"), " "),
  27. OwnerID: ctx.QueryInt64("uid"),
  28. PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
  29. }
  30. if ctx.User != nil && ctx.User.ID == opts.OwnerID {
  31. opts.Searcher = ctx.User
  32. }
  33. // Check visibility.
  34. if ctx.IsSigned && opts.OwnerID > 0 {
  35. if ctx.User.ID == opts.OwnerID {
  36. opts.Private = true
  37. } else {
  38. u, err := models.GetUserByID(opts.OwnerID)
  39. if err != nil {
  40. ctx.JSON(500, api.SearchError{
  41. OK: false,
  42. Error: err.Error(),
  43. })
  44. return
  45. }
  46. if u.IsOrganization() && u.IsOwnedBy(ctx.User.ID) {
  47. opts.Private = true
  48. }
  49. // FIXME: how about collaborators?
  50. }
  51. }
  52. repos, count, err := models.SearchRepositoryByName(opts)
  53. if err != nil {
  54. ctx.JSON(500, api.SearchError{
  55. OK: false,
  56. Error: err.Error(),
  57. })
  58. return
  59. }
  60. var userID int64
  61. if ctx.IsSigned {
  62. userID = ctx.User.ID
  63. }
  64. results := make([]*api.Repository, len(repos))
  65. for i, repo := range repos {
  66. if err = repo.GetOwner(); err != nil {
  67. ctx.JSON(500, api.SearchError{
  68. OK: false,
  69. Error: err.Error(),
  70. })
  71. return
  72. }
  73. accessMode, err := models.AccessLevel(userID, repo)
  74. if err != nil {
  75. ctx.JSON(500, api.SearchError{
  76. OK: false,
  77. Error: err.Error(),
  78. })
  79. }
  80. results[i] = repo.APIFormat(accessMode)
  81. }
  82. ctx.SetLinkHeader(int(count), setting.API.MaxResponseItems)
  83. ctx.JSON(200, api.SearchResults{
  84. OK: true,
  85. Data: results,
  86. })
  87. }
  88. // CreateUserRepo create a repository for a user
  89. func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateRepoOption) {
  90. repo, err := models.CreateRepository(owner, models.CreateRepoOptions{
  91. Name: opt.Name,
  92. Description: opt.Description,
  93. Gitignores: opt.Gitignores,
  94. License: opt.License,
  95. Readme: opt.Readme,
  96. IsPrivate: opt.Private,
  97. AutoInit: opt.AutoInit,
  98. })
  99. if err != nil {
  100. if models.IsErrRepoAlreadyExist(err) ||
  101. models.IsErrNameReserved(err) ||
  102. models.IsErrNamePatternNotAllowed(err) {
  103. ctx.Error(422, "", err)
  104. } else {
  105. if repo != nil {
  106. if err = models.DeleteRepository(ctx.User.ID, repo.ID); err != nil {
  107. log.Error(4, "DeleteRepository: %v", err)
  108. }
  109. }
  110. ctx.Error(500, "CreateRepository", err)
  111. }
  112. return
  113. }
  114. ctx.JSON(201, repo.APIFormat(models.AccessModeOwner))
  115. }
  116. // Create one repository of mine
  117. // see https://github.com/gogits/go-gogs-client/wiki/Repositories#create
  118. func Create(ctx *context.APIContext, opt api.CreateRepoOption) {
  119. // Shouldn't reach this condition, but just in case.
  120. if ctx.User.IsOrganization() {
  121. ctx.Error(422, "", "not allowed creating repository for organization")
  122. return
  123. }
  124. CreateUserRepo(ctx, ctx.User, opt)
  125. }
  126. // CreateOrgRepo create one repository of the organization
  127. func CreateOrgRepo(ctx *context.APIContext, opt api.CreateRepoOption) {
  128. // swagger:route POST /org/{org}/repos createOrgRepo
  129. //
  130. // Consumes:
  131. // - application/json
  132. //
  133. // Produces:
  134. // - application/json
  135. //
  136. // Responses:
  137. // 201: Repository
  138. // 422: validationError
  139. // 403: forbidden
  140. // 500: error
  141. org, err := models.GetOrgByName(ctx.Params(":org"))
  142. if err != nil {
  143. if models.IsErrOrgNotExist(err) {
  144. ctx.Error(422, "", err)
  145. } else {
  146. ctx.Error(500, "GetOrgByName", err)
  147. }
  148. return
  149. }
  150. if !org.IsOwnedBy(ctx.User.ID) {
  151. ctx.Error(403, "", "Given user is not owner of organization.")
  152. return
  153. }
  154. CreateUserRepo(ctx, org, opt)
  155. }
  156. // Migrate migrate remote git repository to gitea
  157. func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
  158. // swagger:route POST /repos/migrate
  159. //
  160. // Consumes:
  161. // - application/json
  162. //
  163. // Produces:
  164. // - application/json
  165. //
  166. // Responses:
  167. // 201: Repository
  168. // 422: validationError
  169. // 500: error
  170. ctxUser := ctx.User
  171. // Not equal means context user is an organization,
  172. // or is another user/organization if current user is admin.
  173. if form.UID != ctxUser.ID {
  174. org, err := models.GetUserByID(form.UID)
  175. if err != nil {
  176. if models.IsErrUserNotExist(err) {
  177. ctx.Error(422, "", err)
  178. } else {
  179. ctx.Error(500, "GetUserByID", err)
  180. }
  181. return
  182. }
  183. ctxUser = org
  184. }
  185. if ctx.HasError() {
  186. ctx.Error(422, "", ctx.GetErrMsg())
  187. return
  188. }
  189. if ctxUser.IsOrganization() && !ctx.User.IsAdmin {
  190. // Check ownership of organization.
  191. if !ctxUser.IsOwnedBy(ctx.User.ID) {
  192. ctx.Error(403, "", "Given user is not owner of organization.")
  193. return
  194. }
  195. }
  196. remoteAddr, err := form.ParseRemoteAddr(ctx.User)
  197. if err != nil {
  198. if models.IsErrInvalidCloneAddr(err) {
  199. addrErr := err.(models.ErrInvalidCloneAddr)
  200. switch {
  201. case addrErr.IsURLError:
  202. ctx.Error(422, "", err)
  203. case addrErr.IsPermissionDenied:
  204. ctx.Error(422, "", "You are not allowed to import local repositories.")
  205. case addrErr.IsInvalidPath:
  206. ctx.Error(422, "", "Invalid local path, it does not exist or not a directory.")
  207. default:
  208. ctx.Error(500, "ParseRemoteAddr", "Unknown error type (ErrInvalidCloneAddr): "+err.Error())
  209. }
  210. } else {
  211. ctx.Error(500, "ParseRemoteAddr", err)
  212. }
  213. return
  214. }
  215. repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
  216. Name: form.RepoName,
  217. Description: form.Description,
  218. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  219. IsMirror: form.Mirror,
  220. RemoteAddr: remoteAddr,
  221. })
  222. if err != nil {
  223. if repo != nil {
  224. if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
  225. log.Error(4, "DeleteRepository: %v", errDelete)
  226. }
  227. }
  228. ctx.Error(500, "MigrateRepository", models.HandleCloneUserCredentials(err.Error(), true))
  229. return
  230. }
  231. log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
  232. ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
  233. }
  234. // Get one repository
  235. func Get(ctx *context.APIContext) {
  236. // swagger:route GET /repos/{username}/{reponame}
  237. //
  238. // Produces:
  239. // - application/json
  240. //
  241. // Responses:
  242. // 200: Repository
  243. // 500: error
  244. ctx.JSON(200, ctx.Repo.Repository.APIFormat(ctx.Repo.AccessMode))
  245. }
  246. // GetByID returns a single Repository
  247. func GetByID(ctx *context.APIContext) {
  248. // swagger:route GET /repositories/{id}
  249. //
  250. // Produces:
  251. // - application/json
  252. //
  253. // Responses:
  254. // 200: Repository
  255. // 500: error
  256. repo, err := models.GetRepositoryByID(ctx.ParamsInt64(":id"))
  257. if err != nil {
  258. if models.IsErrRepoNotExist(err) {
  259. ctx.Status(404)
  260. } else {
  261. ctx.Error(500, "GetRepositoryByID", err)
  262. }
  263. return
  264. }
  265. access, err := models.AccessLevel(ctx.User.ID, repo)
  266. if err != nil {
  267. ctx.Error(500, "AccessLevel", err)
  268. return
  269. } else if access < models.AccessModeRead {
  270. ctx.Status(404)
  271. return
  272. }
  273. ctx.JSON(200, repo.APIFormat(access))
  274. }
  275. // Delete one repository
  276. func Delete(ctx *context.APIContext) {
  277. // swagger:route DELETE /repos/{username}/{reponame}
  278. //
  279. // Produces:
  280. // - application/json
  281. //
  282. // Responses:
  283. // 204: empty
  284. // 403: forbidden
  285. // 500: error
  286. if !ctx.Repo.IsAdmin() {
  287. ctx.Error(403, "", "Must have admin rights")
  288. return
  289. }
  290. owner := ctx.Repo.Owner
  291. repo := ctx.Repo.Repository
  292. if owner.IsOrganization() && !owner.IsOwnedBy(ctx.User.ID) {
  293. ctx.Error(403, "", "Given user is not owner of organization.")
  294. return
  295. }
  296. if err := models.DeleteRepository(owner.ID, repo.ID); err != nil {
  297. ctx.Error(500, "DeleteRepository", err)
  298. return
  299. }
  300. log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name)
  301. ctx.Status(204)
  302. }
  303. // MirrorSync adds a mirrored repository to the sync queue
  304. func MirrorSync(ctx *context.APIContext) {
  305. // swagger:route POST /repos/{username}/{reponame}/mirror-sync repoMirrorSync
  306. //
  307. // Produces:
  308. // - application/json
  309. //
  310. // Responses:
  311. // 200: empty
  312. // 403: forbidden
  313. repo := ctx.Repo.Repository
  314. if !ctx.Repo.IsWriter() {
  315. ctx.Error(403, "MirrorSync", "Must have write access")
  316. }
  317. go models.MirrorQueue.Add(repo.ID)
  318. ctx.Status(200)
  319. }