repo.go 8.1 KB

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