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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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. "fmt"
  7. "path"
  8. "strings"
  9. "github.com/Unknwon/com"
  10. "github.com/gogits/gogs/models"
  11. "github.com/gogits/gogs/modules/auth"
  12. "github.com/gogits/gogs/modules/log"
  13. "github.com/gogits/gogs/modules/middleware"
  14. "github.com/gogits/gogs/modules/setting"
  15. )
  16. type ApiPermission struct {
  17. Admin bool `json:"admin"`
  18. Push bool `json:"push"`
  19. Pull bool `json:"pull"`
  20. }
  21. type ApiRepository struct {
  22. Id int64 `json:"id"`
  23. Owner ApiUser `json:"owner"`
  24. FullName string `json:"full_name"`
  25. Private bool `json:"private"`
  26. Fork bool `json:"fork"`
  27. HtmlUrl string `json:"html_url"`
  28. CloneUrl string `json:"clone_url"`
  29. SshUrl string `json:"ssh_url"`
  30. Permissions ApiPermission `json:"permissions"`
  31. }
  32. func SearchRepos(ctx *middleware.Context) {
  33. opt := models.SearchOption{
  34. Keyword: path.Base(ctx.Query("q")),
  35. Uid: com.StrTo(ctx.Query("uid")).MustInt64(),
  36. Limit: com.StrTo(ctx.Query("limit")).MustInt(),
  37. }
  38. if opt.Limit == 0 {
  39. opt.Limit = 10
  40. }
  41. // Check visibility.
  42. if ctx.IsSigned && opt.Uid > 0 {
  43. if ctx.User.Id == opt.Uid {
  44. opt.Private = true
  45. } else {
  46. u, err := models.GetUserById(opt.Uid)
  47. if err != nil {
  48. ctx.JSON(500, map[string]interface{}{
  49. "ok": false,
  50. "error": err.Error(),
  51. })
  52. return
  53. }
  54. if u.IsOrganization() && u.IsOrgOwner(ctx.User.Id) {
  55. opt.Private = true
  56. }
  57. // FIXME: how about collaborators?
  58. }
  59. }
  60. repos, err := models.SearchRepositoryByName(opt)
  61. if err != nil {
  62. ctx.JSON(500, map[string]interface{}{
  63. "ok": false,
  64. "error": err.Error(),
  65. })
  66. return
  67. }
  68. results := make([]*ApiRepository, len(repos))
  69. for i := range repos {
  70. if err = repos[i].GetOwner(); err != nil {
  71. ctx.JSON(500, map[string]interface{}{
  72. "ok": false,
  73. "error": err.Error(),
  74. })
  75. return
  76. }
  77. results[i] = &ApiRepository{
  78. Id: repos[i].Id,
  79. FullName: path.Join(repos[i].Owner.Name, repos[i].Name),
  80. }
  81. }
  82. ctx.Render.JSON(200, map[string]interface{}{
  83. "ok": true,
  84. "data": results,
  85. })
  86. }
  87. func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) {
  88. u, err := models.GetUserByName(ctx.Query("username"))
  89. if err != nil {
  90. ctx.JSON(500, map[string]interface{}{
  91. "ok": false,
  92. "error": err.Error(),
  93. })
  94. return
  95. }
  96. if !u.ValidtePassword(ctx.Query("password")) {
  97. ctx.JSON(500, map[string]interface{}{
  98. "ok": false,
  99. "error": "username or password is not correct",
  100. })
  101. return
  102. }
  103. ctxUser := u
  104. // Not equal means current user is an organization.
  105. if form.Uid != u.Id {
  106. org, err := models.GetUserById(form.Uid)
  107. if err != nil {
  108. ctx.JSON(500, map[string]interface{}{
  109. "ok": false,
  110. "error": err.Error(),
  111. })
  112. return
  113. }
  114. ctxUser = org
  115. }
  116. if ctx.HasError() {
  117. ctx.JSON(500, map[string]interface{}{
  118. "ok": false,
  119. "error": ctx.GetErrMsg(),
  120. })
  121. return
  122. }
  123. if ctxUser.IsOrganization() {
  124. // Check ownership of organization.
  125. if !ctxUser.IsOrgOwner(u.Id) {
  126. ctx.JSON(403, map[string]interface{}{
  127. "ok": false,
  128. "error": "given user is not owner of organization",
  129. })
  130. return
  131. }
  132. }
  133. authStr := strings.Replace(fmt.Sprintf("://%s:%s",
  134. form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
  135. url := strings.Replace(form.HttpsUrl, "://", authStr+"@", 1)
  136. repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private,
  137. form.Mirror, url)
  138. if err == nil {
  139. log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
  140. ctx.JSON(200, map[string]interface{}{
  141. "ok": true,
  142. "data": "/" + ctxUser.Name + "/" + form.RepoName,
  143. })
  144. return
  145. }
  146. if repo != nil {
  147. if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
  148. log.Error(4, "DeleteRepository: %v", errDelete)
  149. }
  150. }
  151. ctx.JSON(500, map[string]interface{}{
  152. "ok": false,
  153. "error": err.Error(),
  154. })
  155. }
  156. // /user/repos: https://developer.github.com/v3/repos/#list-your-repositories
  157. func ListMyRepos(ctx *middleware.Context) {
  158. if !ctx.IsSigned {
  159. ctx.Error(403)
  160. return
  161. }
  162. ownRepos, err := models.GetRepositories(ctx.User.Id, true)
  163. if err != nil {
  164. ctx.JSON(500, map[string]interface{}{
  165. "ok": false,
  166. "error": err.Error(),
  167. })
  168. return
  169. }
  170. numOwnRepos := len(ownRepos)
  171. collaRepos, err := models.GetCollaborativeRepos(ctx.User.Name)
  172. if err != nil {
  173. ctx.JSON(500, map[string]interface{}{
  174. "ok": false,
  175. "error": err.Error(),
  176. })
  177. return
  178. }
  179. sshUrlFmt := "%s@%s:%s/%s.git"
  180. if setting.SshPort != 22 {
  181. sshUrlFmt = "ssh://%s@%s:%d/%s/%s.git"
  182. }
  183. repos := make([]*ApiRepository, numOwnRepos+len(collaRepos))
  184. // FIXME: make only one loop
  185. for i := range ownRepos {
  186. repos[i] = &ApiRepository{
  187. Id: ownRepos[i].Id,
  188. Owner: ApiUser{
  189. Id: ctx.User.Id,
  190. UserName: ctx.User.Name,
  191. AvatarUrl: string(setting.Protocol) + ctx.User.AvatarLink(),
  192. },
  193. FullName: ctx.User.Name + "/" + ownRepos[i].Name,
  194. Private: ownRepos[i].IsPrivate,
  195. Fork: ownRepos[i].IsFork,
  196. HtmlUrl: setting.AppUrl + ctx.User.Name + "/" + ownRepos[i].Name,
  197. SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, ctx.User.LowerName, ownRepos[i].LowerName),
  198. Permissions: ApiPermission{true, true, true},
  199. }
  200. repos[i].CloneUrl = repos[i].HtmlUrl + ".git"
  201. }
  202. for i := range collaRepos {
  203. if err = collaRepos[i].GetOwner(); err != nil {
  204. ctx.JSON(500, map[string]interface{}{
  205. "ok": false,
  206. "error": err.Error(),
  207. })
  208. return
  209. }
  210. j := i + numOwnRepos
  211. repos[j] = &ApiRepository{
  212. Id: collaRepos[i].Id,
  213. Owner: ApiUser{
  214. Id: collaRepos[i].Owner.Id,
  215. UserName: collaRepos[i].Owner.Name,
  216. AvatarUrl: string(setting.Protocol) + collaRepos[i].Owner.AvatarLink(),
  217. },
  218. FullName: collaRepos[i].Owner.Name + "/" + collaRepos[i].Name,
  219. Private: collaRepos[i].IsPrivate,
  220. Fork: collaRepos[i].IsFork,
  221. HtmlUrl: setting.AppUrl + collaRepos[i].Owner.Name + "/" + collaRepos[i].Name,
  222. SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, collaRepos[i].Owner.LowerName, collaRepos[i].LowerName),
  223. Permissions: ApiPermission{false, collaRepos[i].CanPush, true},
  224. }
  225. repos[j].CloneUrl = repos[j].HtmlUrl + ".git"
  226. // FIXME: cache result to reduce DB query?
  227. if collaRepos[i].Owner.IsOrganization() && collaRepos[i].Owner.IsOrgOwner(ctx.User.Id) {
  228. repos[j].Permissions.Admin = true
  229. }
  230. }
  231. ctx.JSON(200, &repos)
  232. }