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.

repo.go 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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 v1
  5. import (
  6. "path"
  7. "github.com/Unknwon/com"
  8. api "github.com/gogits/go-gogs-client"
  9. "github.com/gogits/gogs/models"
  10. "github.com/gogits/gogs/modules/auth"
  11. "github.com/gogits/gogs/modules/log"
  12. "github.com/gogits/gogs/modules/middleware"
  13. "github.com/gogits/gogs/modules/setting"
  14. )
  15. // ToApiRepository converts repository to API format.
  16. func ToApiRepository(owner *models.User, repo *models.Repository, permission api.Permission) *api.Repository {
  17. cl := repo.CloneLink()
  18. return &api.Repository{
  19. Id: repo.ID,
  20. Owner: *ToApiUser(owner),
  21. FullName: owner.Name + "/" + repo.Name,
  22. Private: repo.IsPrivate,
  23. Fork: repo.IsFork,
  24. HtmlUrl: setting.AppUrl + owner.Name + "/" + repo.Name,
  25. CloneUrl: cl.HTTPS,
  26. SshUrl: cl.SSH,
  27. Permissions: permission,
  28. }
  29. }
  30. func SearchRepos(ctx *middleware.Context) {
  31. opt := models.SearchOption{
  32. Keyword: path.Base(ctx.Query("q")),
  33. Uid: com.StrTo(ctx.Query("uid")).MustInt64(),
  34. Limit: com.StrTo(ctx.Query("limit")).MustInt(),
  35. }
  36. if opt.Limit == 0 {
  37. opt.Limit = 10
  38. }
  39. // Check visibility.
  40. if ctx.IsSigned && opt.Uid > 0 {
  41. if ctx.User.Id == opt.Uid {
  42. opt.Private = true
  43. } else {
  44. u, err := models.GetUserByID(opt.Uid)
  45. if err != nil {
  46. ctx.JSON(500, map[string]interface{}{
  47. "ok": false,
  48. "error": err.Error(),
  49. })
  50. return
  51. }
  52. if u.IsOrganization() && u.IsOwnedBy(ctx.User.Id) {
  53. opt.Private = true
  54. }
  55. // FIXME: how about collaborators?
  56. }
  57. }
  58. repos, err := models.SearchRepositoryByName(opt)
  59. if err != nil {
  60. ctx.JSON(500, map[string]interface{}{
  61. "ok": false,
  62. "error": err.Error(),
  63. })
  64. return
  65. }
  66. results := make([]*api.Repository, len(repos))
  67. for i := range repos {
  68. if err = repos[i].GetOwner(); err != nil {
  69. ctx.JSON(500, map[string]interface{}{
  70. "ok": false,
  71. "error": err.Error(),
  72. })
  73. return
  74. }
  75. results[i] = &api.Repository{
  76. Id: repos[i].ID,
  77. FullName: path.Join(repos[i].Owner.Name, repos[i].Name),
  78. }
  79. }
  80. ctx.JSON(200, map[string]interface{}{
  81. "ok": true,
  82. "data": results,
  83. })
  84. }
  85. // https://github.com/gogits/go-gogs-client/wiki/Repositories#list-your-repositories
  86. func ListMyRepos(ctx *middleware.Context) {
  87. ownRepos, err := models.GetRepositories(ctx.User.Id, true)
  88. if err != nil {
  89. ctx.APIError(500, "GetRepositories", err)
  90. return
  91. }
  92. numOwnRepos := len(ownRepos)
  93. accessibleRepos, err := ctx.User.GetRepositoryAccesses()
  94. if err != nil {
  95. ctx.APIError(500, "GetRepositoryAccesses", err)
  96. return
  97. }
  98. repos := make([]*api.Repository, numOwnRepos+len(accessibleRepos))
  99. for i := range ownRepos {
  100. repos[i] = ToApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true})
  101. }
  102. i := numOwnRepos
  103. for repo, access := range accessibleRepos {
  104. repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{
  105. Admin: access >= models.ACCESS_MODE_ADMIN,
  106. Push: access >= models.ACCESS_MODE_WRITE,
  107. Pull: true,
  108. })
  109. i++
  110. }
  111. ctx.JSON(200, &repos)
  112. }
  113. func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoOption) {
  114. repo, err := models.CreateRepository(owner, models.CreateRepoOptions{
  115. Name: opt.Name,
  116. Description: opt.Description,
  117. Gitignores: opt.Gitignores,
  118. License: opt.License,
  119. Readme: opt.Readme,
  120. IsPrivate: opt.Private,
  121. AutoInit: opt.AutoInit,
  122. })
  123. if err != nil {
  124. if models.IsErrRepoAlreadyExist(err) ||
  125. models.IsErrNameReserved(err) ||
  126. models.IsErrNamePatternNotAllowed(err) {
  127. ctx.APIError(422, "", err)
  128. } else {
  129. if repo != nil {
  130. if err = models.DeleteRepository(ctx.User.Id, repo.ID); err != nil {
  131. log.Error(4, "DeleteRepository: %v", err)
  132. }
  133. }
  134. ctx.APIError(500, "CreateRepository", err)
  135. }
  136. return
  137. }
  138. ctx.JSON(201, ToApiRepository(owner, repo, api.Permission{true, true, true}))
  139. }
  140. // https://github.com/gogits/go-gogs-client/wiki/Repositories#create
  141. func CreateRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
  142. // Shouldn't reach this condition, but just in case.
  143. if ctx.User.IsOrganization() {
  144. ctx.APIError(422, "", "not allowed creating repository for organization")
  145. return
  146. }
  147. createRepo(ctx, ctx.User, opt)
  148. }
  149. func CreateOrgRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
  150. org, err := models.GetOrgByName(ctx.Params(":org"))
  151. if err != nil {
  152. if models.IsErrUserNotExist(err) {
  153. ctx.APIError(422, "", err)
  154. } else {
  155. ctx.APIError(500, "GetOrgByName", err)
  156. }
  157. return
  158. }
  159. if !org.IsOwnedBy(ctx.User.Id) {
  160. ctx.APIError(403, "", "Given user is not owner of organization.")
  161. return
  162. }
  163. createRepo(ctx, org, opt)
  164. }
  165. func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) {
  166. ctxUser := ctx.User
  167. // Not equal means context user is an organization,
  168. // or is another user/organization if current user is admin.
  169. if form.Uid != ctxUser.Id {
  170. org, err := models.GetUserByID(form.Uid)
  171. if err != nil {
  172. if models.IsErrUserNotExist(err) {
  173. ctx.APIError(422, "", err)
  174. } else {
  175. ctx.APIError(500, "GetUserByID", err)
  176. }
  177. return
  178. }
  179. ctxUser = org
  180. }
  181. if ctx.HasError() {
  182. ctx.APIError(422, "", ctx.GetErrMsg())
  183. return
  184. }
  185. if ctxUser.IsOrganization() && !ctx.User.IsAdmin {
  186. // Check ownership of organization.
  187. if !ctxUser.IsOwnedBy(ctx.User.Id) {
  188. ctx.APIError(403, "", "Given user is not owner of organization.")
  189. return
  190. }
  191. }
  192. remoteAddr, err := form.ParseRemoteAddr(ctx.User)
  193. if err != nil {
  194. if models.IsErrInvalidCloneAddr(err) {
  195. addrErr := err.(models.ErrInvalidCloneAddr)
  196. switch {
  197. case addrErr.IsURLError:
  198. ctx.APIError(422, "", err)
  199. case addrErr.IsPermissionDenied:
  200. ctx.APIError(422, "", "You are not allowed to import local repositories.")
  201. case addrErr.IsInvalidPath:
  202. ctx.APIError(422, "", "Invalid local path, it does not exist or not a directory.")
  203. default:
  204. ctx.APIError(500, "ParseRemoteAddr", "Unknown error type (ErrInvalidCloneAddr): "+err.Error())
  205. }
  206. } else {
  207. ctx.APIError(500, "ParseRemoteAddr", err)
  208. }
  209. return
  210. }
  211. repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
  212. Name: form.RepoName,
  213. Description: form.Description,
  214. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  215. IsMirror: form.Mirror,
  216. RemoteAddr: remoteAddr,
  217. })
  218. if err != nil {
  219. if repo != nil {
  220. if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil {
  221. log.Error(4, "DeleteRepository: %v", errDelete)
  222. }
  223. }
  224. ctx.APIError(500, "MigrateRepository", err)
  225. return
  226. }
  227. log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
  228. ctx.JSON(201, ToApiRepository(ctxUser, repo, api.Permission{true, true, true}))
  229. }
  230. func parseOwnerAndRepo(ctx *middleware.Context) (*models.User, *models.Repository) {
  231. owner, err := models.GetUserByName(ctx.Params(":username"))
  232. if err != nil {
  233. if models.IsErrUserNotExist(err) {
  234. ctx.APIError(422, "", err)
  235. } else {
  236. ctx.APIError(500, "GetUserByName", err)
  237. }
  238. return nil, nil
  239. }
  240. repo, err := models.GetRepositoryByName(owner.Id, ctx.Params(":reponame"))
  241. if err != nil {
  242. if models.IsErrRepoNotExist(err) {
  243. ctx.Error(404)
  244. } else {
  245. ctx.APIError(500, "GetRepositoryByName", err)
  246. }
  247. return nil, nil
  248. }
  249. return owner, repo
  250. }
  251. func GetRepo(ctx *middleware.Context) {
  252. owner, repo := parseOwnerAndRepo(ctx)
  253. if ctx.Written() {
  254. return
  255. }
  256. ctx.JSON(200, ToApiRepository(owner, repo, api.Permission{true, true, true}))
  257. }
  258. func DeleteRepo(ctx *middleware.Context) {
  259. owner, repo := parseOwnerAndRepo(ctx)
  260. if ctx.Written() {
  261. return
  262. }
  263. if owner.IsOrganization() && !owner.IsOwnedBy(ctx.User.Id) {
  264. ctx.APIError(403, "", "Given user is not owner of organization.")
  265. return
  266. }
  267. if err := models.DeleteRepository(owner.Id, repo.ID); err != nil {
  268. ctx.APIError(500, "DeleteRepository", err)
  269. return
  270. }
  271. log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name)
  272. ctx.Status(204)
  273. }