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 12 kB

11 years ago
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
11 years ago
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
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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 middleware
  5. import (
  6. "errors"
  7. "fmt"
  8. "net/url"
  9. "strings"
  10. "github.com/Unknwon/macaron"
  11. "github.com/gogits/gogs/models"
  12. "github.com/gogits/gogs/modules/base"
  13. "github.com/gogits/gogs/modules/git"
  14. "github.com/gogits/gogs/modules/log"
  15. "github.com/gogits/gogs/modules/setting"
  16. )
  17. func ApiRepoAssignment() macaron.Handler {
  18. return func(ctx *Context) {
  19. userName := ctx.Params(":username")
  20. repoName := ctx.Params(":reponame")
  21. var (
  22. u *models.User
  23. err error
  24. )
  25. // Collaborators who have write access can be seen as owners.
  26. if ctx.IsSigned {
  27. ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
  28. if err != nil {
  29. ctx.JSON(500, &base.ApiJsonErr{"HasAccess: " + err.Error(), base.DOC_URL})
  30. return
  31. }
  32. ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
  33. }
  34. if !ctx.Repo.IsTrueOwner {
  35. u, err = models.GetUserByName(userName)
  36. if err != nil {
  37. if err == models.ErrUserNotExist {
  38. ctx.Error(404)
  39. } else {
  40. ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL})
  41. }
  42. return
  43. }
  44. } else {
  45. u = ctx.User
  46. }
  47. ctx.Repo.Owner = u
  48. // Organization owner team members are true owners as well.
  49. if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
  50. ctx.Repo.IsTrueOwner = true
  51. }
  52. // Get repository.
  53. repo, err := models.GetRepositoryByName(u.Id, repoName)
  54. if err != nil {
  55. if err == models.ErrRepoNotExist {
  56. ctx.Error(404)
  57. return
  58. }
  59. ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
  60. return
  61. } else if err = repo.GetOwner(); err != nil {
  62. ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
  63. return
  64. }
  65. // Check if the mirror repository owner(mirror repository doesn't have access).
  66. if ctx.IsSigned && !ctx.Repo.IsOwner {
  67. if repo.OwnerId == ctx.User.Id {
  68. ctx.Repo.IsOwner = true
  69. }
  70. // Check if current user has admin permission to repository.
  71. if u.IsOrganization() {
  72. auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
  73. if err != nil {
  74. ctx.JSON(500, &base.ApiJsonErr{"GetHighestAuthorize: " + err.Error(), base.DOC_URL})
  75. return
  76. }
  77. if auth == models.ORG_ADMIN {
  78. ctx.Repo.IsOwner = true
  79. ctx.Repo.IsAdmin = true
  80. }
  81. }
  82. }
  83. // Check access.
  84. if repo.IsPrivate && !ctx.Repo.IsOwner {
  85. if ctx.User == nil {
  86. ctx.Error(404)
  87. return
  88. }
  89. hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
  90. if err != nil {
  91. ctx.JSON(500, &base.ApiJsonErr{"HasAccess: " + err.Error(), base.DOC_URL})
  92. return
  93. } else if !hasAccess {
  94. ctx.Error(404)
  95. return
  96. }
  97. }
  98. ctx.Repo.HasAccess = true
  99. ctx.Repo.Repository = repo
  100. }
  101. }
  102. // RepoRef handles repository reference name including those contain `/`.
  103. func RepoRef() macaron.Handler {
  104. return func(ctx *Context) {
  105. var (
  106. refName string
  107. err error
  108. )
  109. // For API calls.
  110. if ctx.Repo.GitRepo == nil {
  111. repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
  112. gitRepo, err := git.OpenRepository(repoPath)
  113. if err != nil {
  114. ctx.Handle(500, "RepoRef Invalid repo "+repoPath, err)
  115. return
  116. }
  117. ctx.Repo.GitRepo = gitRepo
  118. }
  119. // Get default branch.
  120. if len(ctx.Params("*")) == 0 {
  121. refName = ctx.Repo.Repository.DefaultBranch
  122. if !ctx.Repo.GitRepo.IsBranchExist(refName) {
  123. brs, err := ctx.Repo.GitRepo.GetBranches()
  124. if err != nil {
  125. ctx.Handle(500, "GetBranches", err)
  126. return
  127. }
  128. refName = brs[0]
  129. }
  130. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  131. if err != nil {
  132. ctx.Handle(500, "GetCommitOfBranch", err)
  133. return
  134. }
  135. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  136. ctx.Repo.IsBranch = true
  137. } else {
  138. hasMatched := false
  139. parts := strings.Split(ctx.Params("*"), "/")
  140. for i, part := range parts {
  141. refName = strings.TrimPrefix(refName+"/"+part, "/")
  142. if ctx.Repo.GitRepo.IsBranchExist(refName) ||
  143. ctx.Repo.GitRepo.IsTagExist(refName) {
  144. if i < len(parts)-1 {
  145. ctx.Repo.TreeName = strings.Join(parts[i+1:], "/")
  146. }
  147. hasMatched = true
  148. break
  149. }
  150. }
  151. if !hasMatched && len(parts[0]) == 40 {
  152. refName = parts[0]
  153. ctx.Repo.TreeName = strings.Join(parts[1:], "/")
  154. }
  155. if ctx.Repo.GitRepo.IsBranchExist(refName) {
  156. ctx.Repo.IsBranch = true
  157. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  158. if err != nil {
  159. ctx.Handle(500, "GetCommitOfBranch", err)
  160. return
  161. }
  162. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  163. } else if ctx.Repo.GitRepo.IsTagExist(refName) {
  164. ctx.Repo.IsTag = true
  165. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfTag(refName)
  166. if err != nil {
  167. ctx.Handle(500, "GetCommitOfTag", err)
  168. return
  169. }
  170. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  171. } else if len(refName) == 40 {
  172. ctx.Repo.IsCommit = true
  173. ctx.Repo.CommitId = refName
  174. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
  175. if err != nil {
  176. ctx.Handle(404, "GetCommit", nil)
  177. return
  178. }
  179. } else {
  180. ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
  181. return
  182. }
  183. }
  184. ctx.Repo.BranchName = refName
  185. ctx.Data["BranchName"] = ctx.Repo.BranchName
  186. ctx.Data["CommitId"] = ctx.Repo.CommitId
  187. ctx.Data["IsBranch"] = ctx.Repo.IsBranch
  188. ctx.Data["IsTag"] = ctx.Repo.IsTag
  189. ctx.Data["IsCommit"] = ctx.Repo.IsCommit
  190. ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
  191. if err != nil {
  192. ctx.Handle(500, "CommitsCount", err)
  193. return
  194. }
  195. ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
  196. }
  197. }
  198. func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
  199. return func(ctx *Context) {
  200. var (
  201. displayBare bool // To display bare page if it is a bare repo.
  202. )
  203. if len(args) >= 1 {
  204. displayBare = args[0]
  205. }
  206. var (
  207. u *models.User
  208. err error
  209. )
  210. userName := ctx.Params(":username")
  211. repoName := ctx.Params(":reponame")
  212. refName := ctx.Params(":branchname")
  213. if len(refName) == 0 {
  214. refName = ctx.Params(":path")
  215. }
  216. // Collaborators who have write access can be seen as owners.
  217. if ctx.IsSigned {
  218. ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
  219. if err != nil {
  220. ctx.Handle(500, "HasAccess", err)
  221. return
  222. }
  223. ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
  224. }
  225. if !ctx.Repo.IsTrueOwner {
  226. u, err = models.GetUserByName(userName)
  227. if err != nil {
  228. if err == models.ErrUserNotExist {
  229. ctx.Handle(404, "GetUserByName", err)
  230. } else if redirect {
  231. log.Error(4, "GetUserByName", err)
  232. ctx.Redirect(setting.AppSubUrl + "/")
  233. } else {
  234. ctx.Handle(500, "GetUserByName", err)
  235. }
  236. return
  237. }
  238. } else {
  239. u = ctx.User
  240. }
  241. if u == nil {
  242. if redirect {
  243. ctx.Redirect(setting.AppSubUrl + "/")
  244. return
  245. }
  246. ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository"))
  247. return
  248. }
  249. ctx.Repo.Owner = u
  250. // Organization owner team members are true owners as well.
  251. if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
  252. ctx.Repo.IsTrueOwner = true
  253. }
  254. // Get repository.
  255. repo, err := models.GetRepositoryByName(u.Id, repoName)
  256. if err != nil {
  257. if err == models.ErrRepoNotExist {
  258. ctx.Handle(404, "GetRepositoryByName", err)
  259. return
  260. } else if redirect {
  261. ctx.Redirect(setting.AppSubUrl + "/")
  262. return
  263. }
  264. ctx.Handle(500, "GetRepositoryByName", err)
  265. return
  266. } else if err = repo.GetOwner(); err != nil {
  267. ctx.Handle(500, "GetOwner", err)
  268. return
  269. }
  270. // Check if the mirror repository owner(mirror repository doesn't have access).
  271. if ctx.IsSigned && !ctx.Repo.IsOwner {
  272. if repo.OwnerId == ctx.User.Id {
  273. ctx.Repo.IsOwner = true
  274. }
  275. // Check if current user has admin permission to repository.
  276. if u.IsOrganization() {
  277. auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
  278. if err != nil {
  279. ctx.Handle(500, "GetHighestAuthorize", err)
  280. return
  281. }
  282. if auth == models.ORG_ADMIN {
  283. ctx.Repo.IsOwner = true
  284. ctx.Repo.IsAdmin = true
  285. }
  286. }
  287. }
  288. // Check access.
  289. if repo.IsPrivate && !ctx.Repo.IsOwner {
  290. if ctx.User == nil {
  291. ctx.Handle(404, "HasAccess", nil)
  292. return
  293. }
  294. hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
  295. if err != nil {
  296. ctx.Handle(500, "HasAccess", err)
  297. return
  298. } else if !hasAccess {
  299. ctx.Handle(404, "HasAccess", nil)
  300. return
  301. }
  302. }
  303. ctx.Repo.HasAccess = true
  304. ctx.Data["HasAccess"] = true
  305. if repo.IsMirror {
  306. ctx.Repo.Mirror, err = models.GetMirror(repo.Id)
  307. if err != nil {
  308. ctx.Handle(500, "GetMirror", err)
  309. return
  310. }
  311. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  312. }
  313. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  314. repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
  315. ctx.Repo.Repository = repo
  316. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  317. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  318. if err != nil {
  319. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  320. return
  321. }
  322. ctx.Repo.GitRepo = gitRepo
  323. ctx.Repo.RepoLink, err = repo.RepoLink()
  324. if err != nil {
  325. ctx.Handle(500, "RepoLink", err)
  326. return
  327. }
  328. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  329. tags, err := ctx.Repo.GitRepo.GetTags()
  330. if err != nil {
  331. ctx.Handle(500, "GetTags", err)
  332. return
  333. }
  334. ctx.Data["Tags"] = tags
  335. ctx.Repo.Repository.NumTags = len(tags)
  336. // Non-fork repository will not return error in this method.
  337. if err = repo.GetForkRepo(); err != nil {
  338. ctx.Handle(500, "GetForkRepo", err)
  339. return
  340. }
  341. ctx.Data["Title"] = u.Name + "/" + repo.Name
  342. ctx.Data["Repository"] = repo
  343. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  344. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
  345. ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner
  346. ctx.Data["DisableSSH"] = setting.DisableSSH
  347. ctx.Repo.CloneLink, err = repo.CloneLink()
  348. if err != nil {
  349. ctx.Handle(500, "CloneLink", err)
  350. return
  351. }
  352. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  353. if ctx.Query("go-get") == "1" {
  354. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
  355. }
  356. // repo is bare and display enable
  357. if ctx.Repo.Repository.IsBare {
  358. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  359. // NOTE: to prevent templating error
  360. ctx.Data["BranchName"] = ""
  361. if displayBare {
  362. ctx.HTML(200, "repo/bare")
  363. }
  364. return
  365. }
  366. if ctx.IsSigned {
  367. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id)
  368. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id)
  369. }
  370. ctx.Data["TagName"] = ctx.Repo.TagName
  371. brs, err := ctx.Repo.GitRepo.GetBranches()
  372. if err != nil {
  373. ctx.Handle(500, "GetBranches", err)
  374. return
  375. }
  376. ctx.Data["Branches"] = brs
  377. ctx.Data["BrancheCount"] = len(brs)
  378. // If not branch selected, try default one.
  379. // If default branch doesn't exists, fall back to some other branch.
  380. if ctx.Repo.BranchName == "" {
  381. if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  382. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  383. } else if len(brs) > 0 {
  384. ctx.Repo.BranchName = brs[0]
  385. }
  386. }
  387. ctx.Data["BranchName"] = ctx.Repo.BranchName
  388. ctx.Data["CommitId"] = ctx.Repo.CommitId
  389. }
  390. }
  391. func RequireTrueOwner() macaron.Handler {
  392. return func(ctx *Context) {
  393. if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin {
  394. if !ctx.IsSigned {
  395. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  396. ctx.Redirect(setting.AppSubUrl + "/user/login")
  397. return
  398. }
  399. ctx.Handle(404, ctx.Req.RequestURI, nil)
  400. return
  401. }
  402. }
  403. }
  404. // GitHookService checks if repository Git hooks service has been enabled.
  405. func GitHookService() macaron.Handler {
  406. return func(ctx *Context) {
  407. if !ctx.User.AllowGitHook && !ctx.User.IsAdmin {
  408. ctx.Handle(404, "GitHookService", nil)
  409. return
  410. }
  411. }
  412. }