repo.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. package repo
  2. import (
  3. "gitote/gitote/models"
  4. "gitote/gitote/models/errors"
  5. "gitote/gitote/pkg/context"
  6. "gitote/gitote/pkg/form"
  7. "gitote/gitote/pkg/setting"
  8. "gitote/gitote/routes/api/v1/convert"
  9. "path"
  10. raven "github.com/getsentry/raven-go"
  11. api "gitlab.com/gitote/go-gitote-client"
  12. log "gopkg.in/clog.v1"
  13. )
  14. func Search(c *context.APIContext) {
  15. opts := &models.SearchRepoOptions{
  16. Keyword: path.Base(c.Query("q")),
  17. OwnerID: c.QueryInt64("uid"),
  18. PageSize: convert.ToCorrectPageSize(c.QueryInt("limit")),
  19. Page: c.QueryInt("page"),
  20. }
  21. // Check visibility.
  22. if c.IsLogged && opts.OwnerID > 0 {
  23. if c.User.ID == opts.OwnerID {
  24. opts.Private = true
  25. } else {
  26. u, err := models.GetUserByID(opts.OwnerID)
  27. if err != nil {
  28. c.JSON(500, map[string]interface{}{
  29. "ok": false,
  30. "error": err.Error(),
  31. })
  32. return
  33. }
  34. if u.IsOrganization() && u.IsOwnedBy(c.User.ID) {
  35. opts.Private = true
  36. }
  37. // FIXME: how about collaborators?
  38. }
  39. }
  40. repos, count, err := models.SearchRepositoryByName(opts)
  41. if err != nil {
  42. c.JSON(500, map[string]interface{}{
  43. "ok": false,
  44. "error": err.Error(),
  45. })
  46. return
  47. }
  48. if err = models.RepositoryList(repos).LoadAttributes(); err != nil {
  49. c.JSON(500, map[string]interface{}{
  50. "ok": false,
  51. "error": err.Error(),
  52. })
  53. return
  54. }
  55. results := make([]*api.Repository, len(repos))
  56. for i := range repos {
  57. results[i] = repos[i].APIFormat(nil)
  58. }
  59. c.SetLinkHeader(int(count), opts.PageSize)
  60. c.JSON(200, map[string]interface{}{
  61. "ok": true,
  62. "data": results,
  63. })
  64. }
  65. func listUserRepositories(c *context.APIContext, username string) {
  66. user, err := models.GetUserByName(username)
  67. if err != nil {
  68. c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
  69. return
  70. }
  71. // Only list public repositories if user requests someone else's repository list,
  72. // or an organization isn't a member of.
  73. var ownRepos []*models.Repository
  74. if user.IsOrganization() {
  75. ownRepos, _, err = user.GetUserRepositories(c.User.ID, 1, user.NumRepos)
  76. } else {
  77. ownRepos, err = models.GetUserRepositories(&models.UserRepoOptions{
  78. UserID: user.ID,
  79. Private: c.User.ID == user.ID,
  80. Page: 1,
  81. PageSize: user.NumRepos,
  82. })
  83. }
  84. if err != nil {
  85. c.Error(500, "GetUserRepositories", err)
  86. return
  87. }
  88. if err = models.RepositoryList(ownRepos).LoadAttributes(); err != nil {
  89. c.Error(500, "LoadAttributes(ownRepos)", err)
  90. return
  91. }
  92. // Early return for querying other user's repositories
  93. if c.User.ID != user.ID {
  94. repos := make([]*api.Repository, len(ownRepos))
  95. for i := range ownRepos {
  96. repos[i] = ownRepos[i].APIFormat(&api.Permission{true, true, true})
  97. }
  98. c.JSON(200, &repos)
  99. return
  100. }
  101. accessibleRepos, err := user.GetRepositoryAccesses()
  102. if err != nil {
  103. c.Error(500, "GetRepositoryAccesses", err)
  104. return
  105. }
  106. numOwnRepos := len(ownRepos)
  107. repos := make([]*api.Repository, numOwnRepos+len(accessibleRepos))
  108. for i := range ownRepos {
  109. repos[i] = ownRepos[i].APIFormat(&api.Permission{true, true, true})
  110. }
  111. i := numOwnRepos
  112. for repo, access := range accessibleRepos {
  113. repos[i] = repo.APIFormat(&api.Permission{
  114. Admin: access >= models.ACCESS_MODE_ADMIN,
  115. Push: access >= models.ACCESS_MODE_WRITE,
  116. Pull: true,
  117. })
  118. i++
  119. }
  120. c.JSON(200, &repos)
  121. }
  122. func ListMyRepos(c *context.APIContext) {
  123. listUserRepositories(c, c.User.Name)
  124. }
  125. func ListUserRepositories(c *context.APIContext) {
  126. listUserRepositories(c, c.Params(":username"))
  127. }
  128. func ListOrgRepositories(c *context.APIContext) {
  129. listUserRepositories(c, c.Params(":org"))
  130. }
  131. func CreateUserRepo(c *context.APIContext, owner *models.User, opt api.CreateRepoOption) {
  132. repo, err := models.CreateRepository(c.User, owner, models.CreateRepoOptions{
  133. Name: opt.Name,
  134. Description: opt.Description,
  135. Gitignores: opt.Gitignores,
  136. License: opt.License,
  137. Readme: opt.Readme,
  138. IsPrivate: opt.Private,
  139. AutoInit: opt.AutoInit,
  140. })
  141. if err != nil {
  142. if models.IsErrRepoAlreadyExist(err) ||
  143. models.IsErrNameReserved(err) ||
  144. models.IsErrNamePatternNotAllowed(err) {
  145. c.Error(422, "", err)
  146. } else {
  147. if repo != nil {
  148. if err = models.DeleteRepository(c.User.ID, repo.ID); err != nil {
  149. raven.CaptureErrorAndWait(err, nil)
  150. log.Error(2, "DeleteRepository: %v", err)
  151. }
  152. }
  153. c.Error(500, "CreateRepository", err)
  154. }
  155. return
  156. }
  157. c.JSON(201, repo.APIFormat(&api.Permission{true, true, true}))
  158. }
  159. func Create(c *context.APIContext, opt api.CreateRepoOption) {
  160. // Shouldn't reach this condition, but just in case.
  161. if c.User.IsOrganization() {
  162. c.Error(422, "", "not allowed creating repository for organization")
  163. return
  164. }
  165. CreateUserRepo(c, c.User, opt)
  166. }
  167. func CreateOrgRepo(c *context.APIContext, opt api.CreateRepoOption) {
  168. org, err := models.GetOrgByName(c.Params(":org"))
  169. if err != nil {
  170. if errors.IsUserNotExist(err) {
  171. c.Error(422, "", err)
  172. } else {
  173. c.Error(500, "GetOrgByName", err)
  174. }
  175. return
  176. }
  177. if !org.IsOwnedBy(c.User.ID) {
  178. c.Error(403, "", "Given user is not owner of organization.")
  179. return
  180. }
  181. CreateUserRepo(c, org, opt)
  182. }
  183. func Migrate(c *context.APIContext, f form.MigrateRepo) {
  184. ctxUser := c.User
  185. // Not equal means context user is an organization,
  186. // or is another user/organization if current user is admin.
  187. if f.Uid != ctxUser.ID {
  188. org, err := models.GetUserByID(f.Uid)
  189. if err != nil {
  190. if errors.IsUserNotExist(err) {
  191. c.Error(422, "", err)
  192. } else {
  193. c.Error(500, "GetUserByID", err)
  194. }
  195. return
  196. } else if !org.IsOrganization() && !c.User.IsAdmin {
  197. c.Error(403, "", "Given user is not an organization")
  198. return
  199. }
  200. ctxUser = org
  201. }
  202. if c.HasError() {
  203. c.Error(422, "", c.GetErrMsg())
  204. return
  205. }
  206. if ctxUser.IsOrganization() && !c.User.IsAdmin {
  207. // Check ownership of organization.
  208. if !ctxUser.IsOwnedBy(c.User.ID) {
  209. c.Error(403, "", "Given user is not owner of organization")
  210. return
  211. }
  212. }
  213. remoteAddr, err := f.ParseRemoteAddr(c.User)
  214. if err != nil {
  215. if models.IsErrInvalidCloneAddr(err) {
  216. addrErr := err.(models.ErrInvalidCloneAddr)
  217. switch {
  218. case addrErr.IsURLError:
  219. c.Error(422, "", err)
  220. case addrErr.IsPermissionDenied:
  221. c.Error(422, "", "You are not allowed to import local repositories")
  222. case addrErr.IsInvalidPath:
  223. c.Error(422, "", "Invalid local path, it does not exist or not a directory")
  224. default:
  225. c.Error(500, "ParseRemoteAddr", "Unknown error type (ErrInvalidCloneAddr): "+err.Error())
  226. }
  227. } else {
  228. c.Error(500, "ParseRemoteAddr", err)
  229. }
  230. return
  231. }
  232. repo, err := models.MigrateRepository(c.User, ctxUser, models.MigrateRepoOptions{
  233. Name: f.RepoName,
  234. Description: f.Description,
  235. IsPrivate: f.Private || setting.Repository.ForcePrivate,
  236. IsMirror: f.Mirror,
  237. RemoteAddr: remoteAddr,
  238. })
  239. if err != nil {
  240. if repo != nil {
  241. if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
  242. raven.CaptureErrorAndWait(err, nil)
  243. log.Error(2, "DeleteRepository: %v", errDelete)
  244. }
  245. }
  246. if errors.IsReachLimitOfRepo(err) {
  247. c.Error(422, "", err)
  248. } else {
  249. c.Error(500, "MigrateRepository", models.HandleMirrorCredentials(err.Error(), true))
  250. }
  251. return
  252. }
  253. log.Trace("Repository migrated: %s/%s", ctxUser.Name, f.RepoName)
  254. c.JSON(201, repo.APIFormat(&api.Permission{true, true, true}))
  255. }
  256. func parseOwnerAndRepo(c *context.APIContext) (*models.User, *models.Repository) {
  257. owner, err := models.GetUserByName(c.Params(":username"))
  258. if err != nil {
  259. if errors.IsUserNotExist(err) {
  260. c.Error(422, "", err)
  261. } else {
  262. c.Error(500, "GetUserByName", err)
  263. }
  264. return nil, nil
  265. }
  266. repo, err := models.GetRepositoryByName(owner.ID, c.Params(":reponame"))
  267. if err != nil {
  268. if errors.IsRepoNotExist(err) {
  269. c.Status(404)
  270. } else {
  271. c.Error(500, "GetRepositoryByName", err)
  272. }
  273. return nil, nil
  274. }
  275. return owner, repo
  276. }
  277. func Get(c *context.APIContext) {
  278. _, repo := parseOwnerAndRepo(c)
  279. if c.Written() {
  280. return
  281. }
  282. c.JSON(200, repo.APIFormat(&api.Permission{
  283. Admin: c.Repo.IsAdmin(),
  284. Push: c.Repo.IsWriter(),
  285. Pull: true,
  286. }))
  287. }
  288. func Delete(c *context.APIContext) {
  289. owner, repo := parseOwnerAndRepo(c)
  290. if c.Written() {
  291. return
  292. }
  293. if owner.IsOrganization() && !owner.IsOwnedBy(c.User.ID) {
  294. c.Error(403, "", "Given user is not owner of organization.")
  295. return
  296. }
  297. if err := models.DeleteRepository(owner.ID, repo.ID); err != nil {
  298. c.Error(500, "DeleteRepository", err)
  299. return
  300. }
  301. log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name)
  302. c.Status(204)
  303. }
  304. func ListForks(c *context.APIContext) {
  305. forks, err := c.Repo.Repository.GetForks()
  306. if err != nil {
  307. c.Error(500, "GetForks", err)
  308. return
  309. }
  310. apiForks := make([]*api.Repository, len(forks))
  311. for i := range forks {
  312. if err := forks[i].GetOwner(); err != nil {
  313. c.Error(500, "GetOwner", err)
  314. return
  315. }
  316. apiForks[i] = forks[i].APIFormat(&api.Permission{
  317. Admin: c.User.IsAdminOfRepo(forks[i]),
  318. Push: c.User.IsWriterOfRepo(forks[i]),
  319. Pull: true,
  320. })
  321. }
  322. c.JSON(200, &apiForks)
  323. }
  324. func MirrorSync(c *context.APIContext) {
  325. _, repo := parseOwnerAndRepo(c)
  326. if c.Written() {
  327. return
  328. } else if !repo.IsMirror {
  329. c.Status(404)
  330. return
  331. }
  332. go models.MirrorQueue.Add(repo.ID)
  333. c.Status(202)
  334. }