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
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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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/git"
  13. "github.com/gogits/gogs/modules/log"
  14. "github.com/gogits/gogs/modules/setting"
  15. )
  16. // FIXME: response error in JSON.
  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.Handle(500, "HasAccess", err)
  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.Handle(500, "GetUserByName", err)
  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.IsOrgOwner(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.Handle(500, "GetRepositoryByName", err)
  60. return
  61. } else if err = repo.GetOwner(); err != nil {
  62. ctx.Handle(500, "GetOwner", err)
  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.Handle(500, "GetHighestAuthorize", err)
  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.Handle(500, "HasAccess", err)
  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. // Get default branch.
  110. if len(ctx.Params("*")) == 0 {
  111. refName = ctx.Repo.Repository.DefaultBranch
  112. if !ctx.Repo.GitRepo.IsBranchExist(refName) {
  113. brs, err := ctx.Repo.GitRepo.GetBranches()
  114. if err != nil {
  115. ctx.Handle(500, "GetBranches", err)
  116. return
  117. }
  118. refName = brs[0]
  119. }
  120. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  121. if err != nil {
  122. ctx.Handle(500, "GetCommitOfBranch", err)
  123. return
  124. }
  125. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  126. ctx.Repo.IsBranch = true
  127. } else {
  128. hasMatched := false
  129. parts := strings.Split(ctx.Params("*"), "/")
  130. for i, part := range parts {
  131. refName = strings.TrimPrefix(refName+"/"+part, "/")
  132. if ctx.Repo.GitRepo.IsBranchExist(refName) ||
  133. ctx.Repo.GitRepo.IsTagExist(refName) {
  134. if i < len(parts)-1 {
  135. ctx.Repo.TreeName = strings.Join(parts[i+1:], "/")
  136. }
  137. hasMatched = true
  138. break
  139. }
  140. }
  141. if !hasMatched && len(parts[0]) == 40 {
  142. refName = parts[0]
  143. ctx.Repo.TreeName = strings.Join(parts[1:], "/")
  144. }
  145. if ctx.Repo.GitRepo.IsBranchExist(refName) {
  146. ctx.Repo.IsBranch = true
  147. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  148. if err != nil {
  149. ctx.Handle(500, "GetCommitOfBranch", err)
  150. return
  151. }
  152. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  153. } else if ctx.Repo.GitRepo.IsTagExist(refName) {
  154. ctx.Repo.IsTag = true
  155. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfTag(refName)
  156. if err != nil {
  157. ctx.Handle(500, "GetCommitOfTag", err)
  158. return
  159. }
  160. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  161. } else if len(refName) == 40 {
  162. ctx.Repo.IsCommit = true
  163. ctx.Repo.CommitId = refName
  164. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
  165. if err != nil {
  166. ctx.Handle(404, "GetCommit", nil)
  167. return
  168. }
  169. } else {
  170. ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
  171. return
  172. }
  173. }
  174. ctx.Repo.BranchName = refName
  175. ctx.Data["BranchName"] = ctx.Repo.BranchName
  176. ctx.Data["CommitId"] = ctx.Repo.CommitId
  177. ctx.Data["IsBranch"] = ctx.Repo.IsBranch
  178. ctx.Data["IsTag"] = ctx.Repo.IsTag
  179. ctx.Data["IsCommit"] = ctx.Repo.IsCommit
  180. ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
  181. if err != nil {
  182. ctx.Handle(500, "CommitsCount", err)
  183. return
  184. }
  185. ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
  186. }
  187. }
  188. func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
  189. return func(ctx *Context) {
  190. var (
  191. displayBare bool // To display bare page if it is a bare repo.
  192. )
  193. if len(args) >= 1 {
  194. displayBare = args[0]
  195. }
  196. var (
  197. u *models.User
  198. err error
  199. )
  200. userName := ctx.Params(":username")
  201. repoName := ctx.Params(":reponame")
  202. refName := ctx.Params(":branchname")
  203. if len(refName) == 0 {
  204. refName = ctx.Params(":path")
  205. }
  206. // Collaborators who have write access can be seen as owners.
  207. if ctx.IsSigned {
  208. ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
  209. if err != nil {
  210. ctx.Handle(500, "HasAccess", err)
  211. return
  212. }
  213. ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
  214. }
  215. if !ctx.Repo.IsTrueOwner {
  216. u, err = models.GetUserByName(userName)
  217. if err != nil {
  218. if err == models.ErrUserNotExist {
  219. ctx.Handle(404, "GetUserByName", err)
  220. } else if redirect {
  221. log.Error(4, "GetUserByName", err)
  222. ctx.Redirect(setting.AppSubUrl + "/")
  223. } else {
  224. ctx.Handle(500, "GetUserByName", err)
  225. }
  226. return
  227. }
  228. } else {
  229. u = ctx.User
  230. }
  231. if u == nil {
  232. if redirect {
  233. ctx.Redirect(setting.AppSubUrl + "/")
  234. return
  235. }
  236. ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository"))
  237. return
  238. }
  239. ctx.Repo.Owner = u
  240. // Organization owner team members are true owners as well.
  241. if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
  242. ctx.Repo.IsTrueOwner = true
  243. }
  244. // Get repository.
  245. repo, err := models.GetRepositoryByName(u.Id, repoName)
  246. if err != nil {
  247. if err == models.ErrRepoNotExist {
  248. ctx.Handle(404, "GetRepositoryByName", err)
  249. return
  250. } else if redirect {
  251. ctx.Redirect(setting.AppSubUrl + "/")
  252. return
  253. }
  254. ctx.Handle(500, "GetRepositoryByName", err)
  255. return
  256. } else if err = repo.GetOwner(); err != nil {
  257. ctx.Handle(500, "GetOwner", err)
  258. return
  259. }
  260. // Check if the mirror repository owner(mirror repository doesn't have access).
  261. if ctx.IsSigned && !ctx.Repo.IsOwner {
  262. if repo.OwnerId == ctx.User.Id {
  263. ctx.Repo.IsOwner = true
  264. }
  265. // Check if current user has admin permission to repository.
  266. if u.IsOrganization() {
  267. auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
  268. if err != nil {
  269. ctx.Handle(500, "GetHighestAuthorize", err)
  270. return
  271. }
  272. if auth == models.ORG_ADMIN {
  273. ctx.Repo.IsOwner = true
  274. ctx.Repo.IsAdmin = true
  275. }
  276. }
  277. }
  278. // Check access.
  279. if repo.IsPrivate && !ctx.Repo.IsOwner {
  280. if ctx.User == nil {
  281. ctx.Handle(404, "HasAccess", nil)
  282. return
  283. }
  284. hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
  285. if err != nil {
  286. ctx.Handle(500, "HasAccess", err)
  287. return
  288. } else if !hasAccess {
  289. ctx.Handle(404, "HasAccess", nil)
  290. return
  291. }
  292. }
  293. ctx.Repo.HasAccess = true
  294. ctx.Data["HasAccess"] = true
  295. if repo.IsMirror {
  296. ctx.Repo.Mirror, err = models.GetMirror(repo.Id)
  297. if err != nil {
  298. ctx.Handle(500, "GetMirror", err)
  299. return
  300. }
  301. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  302. }
  303. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  304. repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
  305. ctx.Repo.Repository = repo
  306. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  307. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  308. if err != nil {
  309. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  310. return
  311. }
  312. ctx.Repo.GitRepo = gitRepo
  313. ctx.Repo.RepoLink, err = repo.RepoLink()
  314. if err != nil {
  315. ctx.Handle(500, "RepoLink", err)
  316. return
  317. }
  318. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  319. tags, err := ctx.Repo.GitRepo.GetTags()
  320. if err != nil {
  321. ctx.Handle(500, "GetTags", err)
  322. return
  323. }
  324. ctx.Data["Tags"] = tags
  325. ctx.Repo.Repository.NumTags = len(tags)
  326. // Non-fork repository will not return error in this method.
  327. if err = repo.GetForkRepo(); err != nil {
  328. ctx.Handle(500, "GetForkRepo", err)
  329. return
  330. }
  331. ctx.Data["Title"] = u.Name + "/" + repo.Name
  332. ctx.Data["Repository"] = repo
  333. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  334. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
  335. ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner
  336. if setting.SshPort != 22 {
  337. ctx.Repo.CloneLink.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, u.LowerName, repo.LowerName)
  338. } else {
  339. ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, u.LowerName, repo.LowerName)
  340. }
  341. ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, u.LowerName, repo.LowerName)
  342. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  343. if ctx.Repo.Repository.IsGoget {
  344. ctx.Data["GoGetLink"] = fmt.Sprintf("%s%s/%s", setting.AppUrl, u.LowerName, repo.LowerName)
  345. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
  346. }
  347. // repo is bare and display enable
  348. if ctx.Repo.Repository.IsBare {
  349. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  350. if displayBare {
  351. ctx.HTML(200, "repo/bare")
  352. }
  353. return
  354. }
  355. if ctx.IsSigned {
  356. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id)
  357. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id)
  358. }
  359. ctx.Data["TagName"] = ctx.Repo.TagName
  360. brs, err := ctx.Repo.GitRepo.GetBranches()
  361. if err != nil {
  362. ctx.Handle(500, "GetBranches", err)
  363. return
  364. }
  365. ctx.Data["Branches"] = brs
  366. ctx.Data["BrancheCount"] = len(brs)
  367. // If not branch selected, try default one.
  368. // If default branch doesn't exists, fall back to some other branch.
  369. if ctx.Repo.BranchName == "" {
  370. if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  371. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  372. } else if len(brs) > 0 {
  373. ctx.Repo.BranchName = brs[0]
  374. }
  375. }
  376. ctx.Data["BranchName"] = ctx.Repo.BranchName
  377. ctx.Data["CommitId"] = ctx.Repo.CommitId
  378. }
  379. }
  380. func RequireTrueOwner() macaron.Handler {
  381. return func(ctx *Context) {
  382. if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin {
  383. if !ctx.IsSigned {
  384. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  385. ctx.Redirect(setting.AppSubUrl + "/user/login")
  386. return
  387. }
  388. ctx.Handle(404, ctx.Req.RequestURI, nil)
  389. return
  390. }
  391. }
  392. }
  393. // GitHookService checks if repsitory Git hooks service has been enabled.
  394. func GitHookService() macaron.Handler {
  395. return func(ctx *Context) {
  396. if !setting.Service.EnableGitHooks {
  397. ctx.Handle(404, "GitHookService", nil)
  398. return
  399. }
  400. }
  401. }