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 9.9 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. // RepoRef handles repository reference name including those contain `/`.
  17. func RepoRef() macaron.Handler {
  18. return func(ctx *Context) {
  19. var (
  20. refName string
  21. err error
  22. )
  23. // Get default branch.
  24. if len(ctx.Params("*")) == 0 {
  25. refName = ctx.Repo.Repository.DefaultBranch
  26. if !ctx.Repo.GitRepo.IsBranchExist(refName) {
  27. brs, err := ctx.Repo.GitRepo.GetBranches()
  28. if err != nil {
  29. ctx.Handle(500, "GetBranches", err)
  30. return
  31. }
  32. refName = brs[0]
  33. }
  34. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  35. if err != nil {
  36. ctx.Handle(500, "GetCommitOfBranch", err)
  37. return
  38. }
  39. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  40. ctx.Repo.IsBranch = true
  41. } else {
  42. hasMatched := false
  43. parts := strings.Split(ctx.Params("*"), "/")
  44. for i, part := range parts {
  45. refName = strings.TrimPrefix(refName+"/"+part, "/")
  46. if ctx.Repo.GitRepo.IsBranchExist(refName) ||
  47. ctx.Repo.GitRepo.IsTagExist(refName) {
  48. if i < len(parts)-1 {
  49. ctx.Repo.TreeName = strings.Join(parts[i+1:], "/")
  50. }
  51. hasMatched = true
  52. break
  53. }
  54. }
  55. if !hasMatched && len(parts[0]) == 40 {
  56. refName = parts[0]
  57. ctx.Repo.TreeName = strings.Join(parts[1:], "/")
  58. }
  59. if ctx.Repo.GitRepo.IsBranchExist(refName) {
  60. ctx.Repo.IsBranch = true
  61. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  62. if err != nil {
  63. ctx.Handle(500, "GetCommitOfBranch", err)
  64. return
  65. }
  66. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  67. } else if ctx.Repo.GitRepo.IsTagExist(refName) {
  68. ctx.Repo.IsTag = true
  69. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfTag(refName)
  70. if err != nil {
  71. ctx.Handle(500, "GetCommitOfTag", err)
  72. return
  73. }
  74. ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
  75. } else if len(refName) == 40 {
  76. ctx.Repo.IsCommit = true
  77. ctx.Repo.CommitId = refName
  78. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
  79. if err != nil {
  80. ctx.Handle(404, "GetCommit", nil)
  81. return
  82. }
  83. } else {
  84. ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
  85. return
  86. }
  87. }
  88. ctx.Repo.BranchName = refName
  89. ctx.Data["BranchName"] = ctx.Repo.BranchName
  90. ctx.Data["CommitId"] = ctx.Repo.CommitId
  91. ctx.Data["IsBranch"] = ctx.Repo.IsBranch
  92. ctx.Data["IsTag"] = ctx.Repo.IsTag
  93. ctx.Data["IsCommit"] = ctx.Repo.IsCommit
  94. ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
  95. if err != nil {
  96. ctx.Handle(500, "CommitsCount", err)
  97. return
  98. }
  99. ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
  100. }
  101. }
  102. func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
  103. return func(ctx *Context) {
  104. var (
  105. displayBare bool // To display bare page if it is a bare repo.
  106. )
  107. if len(args) >= 1 {
  108. displayBare = args[0]
  109. }
  110. var (
  111. u *models.User
  112. err error
  113. )
  114. userName := ctx.Params(":username")
  115. repoName := ctx.Params(":reponame")
  116. refName := ctx.Params(":branchname")
  117. if len(refName) == 0 {
  118. refName = ctx.Params(":path")
  119. }
  120. // Collaborators who have write access can be seen as owners.
  121. if ctx.IsSigned {
  122. ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
  123. if err != nil {
  124. ctx.Handle(500, "HasAccess", err)
  125. return
  126. }
  127. ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
  128. }
  129. if !ctx.Repo.IsTrueOwner {
  130. u, err = models.GetUserByName(userName)
  131. if err != nil {
  132. if err == models.ErrUserNotExist {
  133. ctx.Handle(404, "GetUserByName", err)
  134. } else if redirect {
  135. log.Error(4, "GetUserByName", err)
  136. ctx.Redirect(setting.AppSubUrl + "/")
  137. } else {
  138. ctx.Handle(500, "GetUserByName", err)
  139. }
  140. return
  141. }
  142. } else {
  143. u = ctx.User
  144. }
  145. if u == nil {
  146. if redirect {
  147. ctx.Redirect(setting.AppSubUrl + "/")
  148. return
  149. }
  150. ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository"))
  151. return
  152. }
  153. ctx.Repo.Owner = u
  154. // Organization owner team members are true owners as well.
  155. if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
  156. ctx.Repo.IsTrueOwner = true
  157. }
  158. // Get repository.
  159. repo, err := models.GetRepositoryByName(u.Id, repoName)
  160. if err != nil {
  161. if err == models.ErrRepoNotExist {
  162. ctx.Handle(404, "GetRepositoryByName", err)
  163. return
  164. } else if redirect {
  165. ctx.Redirect(setting.AppSubUrl + "/")
  166. return
  167. }
  168. ctx.Handle(500, "GetRepositoryByName", err)
  169. return
  170. } else if err = repo.GetOwner(); err != nil {
  171. ctx.Handle(500, "GetOwner", err)
  172. return
  173. }
  174. // Check if the mirror repository owner(mirror repository doesn't have access).
  175. if ctx.IsSigned && !ctx.Repo.IsOwner {
  176. if repo.OwnerId == ctx.User.Id {
  177. ctx.Repo.IsOwner = true
  178. }
  179. // Check if current user has admin permission to repository.
  180. if u.IsOrganization() {
  181. auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
  182. if err != nil {
  183. ctx.Handle(500, "GetHighestAuthorize", err)
  184. return
  185. }
  186. if auth == models.ORG_ADMIN {
  187. ctx.Repo.IsOwner = true
  188. ctx.Repo.IsAdmin = true
  189. }
  190. }
  191. }
  192. // Check access.
  193. if repo.IsPrivate && !ctx.Repo.IsOwner {
  194. if ctx.User == nil {
  195. ctx.Handle(404, "HasAccess", nil)
  196. return
  197. }
  198. hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
  199. if err != nil {
  200. ctx.Handle(500, "HasAccess", err)
  201. return
  202. } else if !hasAccess {
  203. ctx.Handle(404, "HasAccess", nil)
  204. return
  205. }
  206. }
  207. ctx.Repo.HasAccess = true
  208. ctx.Data["HasAccess"] = true
  209. if repo.IsMirror {
  210. ctx.Repo.Mirror, err = models.GetMirror(repo.Id)
  211. if err != nil {
  212. ctx.Handle(500, "GetMirror", err)
  213. return
  214. }
  215. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  216. }
  217. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  218. repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
  219. ctx.Repo.Repository = repo
  220. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  221. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  222. if err != nil {
  223. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  224. return
  225. }
  226. ctx.Repo.GitRepo = gitRepo
  227. ctx.Repo.RepoLink, err = repo.RepoLink()
  228. if err != nil {
  229. ctx.Handle(500, "RepoLink", err)
  230. return
  231. }
  232. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  233. tags, err := ctx.Repo.GitRepo.GetTags()
  234. if err != nil {
  235. ctx.Handle(500, "GetTags", err)
  236. return
  237. }
  238. ctx.Data["Tags"] = tags
  239. ctx.Repo.Repository.NumTags = len(tags)
  240. // Non-fork repository will not return error in this method.
  241. if err = repo.GetForkRepo(); err != nil {
  242. ctx.Handle(500, "GetForkRepo", err)
  243. return
  244. }
  245. ctx.Data["Title"] = u.Name + "/" + repo.Name
  246. ctx.Data["Repository"] = repo
  247. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  248. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
  249. ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner
  250. if setting.SshPort != 22 {
  251. ctx.Repo.CloneLink.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, u.LowerName, repo.LowerName)
  252. } else {
  253. ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, u.LowerName, repo.LowerName)
  254. }
  255. ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, u.LowerName, repo.LowerName)
  256. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  257. if ctx.Repo.Repository.IsGoget {
  258. ctx.Data["GoGetLink"] = fmt.Sprintf("%s%s/%s", setting.AppUrl, u.LowerName, repo.LowerName)
  259. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
  260. }
  261. // repo is bare and display enable
  262. if ctx.Repo.Repository.IsBare {
  263. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  264. if displayBare {
  265. ctx.HTML(200, "repo/bare")
  266. }
  267. return
  268. }
  269. if ctx.IsSigned {
  270. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id)
  271. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id)
  272. }
  273. ctx.Data["TagName"] = ctx.Repo.TagName
  274. brs, err := ctx.Repo.GitRepo.GetBranches()
  275. if err != nil {
  276. ctx.Handle(500, "GetBranches", err)
  277. return
  278. }
  279. ctx.Data["Branches"] = brs
  280. ctx.Data["BrancheCount"] = len(brs)
  281. // If not branch selected, try default one.
  282. // If default branch doesn't exists, fall back to some other branch.
  283. if ctx.Repo.BranchName == "" {
  284. if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  285. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  286. } else if len(brs) > 0 {
  287. ctx.Repo.BranchName = brs[0]
  288. }
  289. }
  290. ctx.Data["BranchName"] = ctx.Repo.BranchName
  291. ctx.Data["CommitId"] = ctx.Repo.CommitId
  292. }
  293. }
  294. func RequireTrueOwner() macaron.Handler {
  295. return func(ctx *Context) {
  296. if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin {
  297. if !ctx.IsSigned {
  298. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  299. ctx.Redirect(setting.AppSubUrl + "/user/login")
  300. return
  301. }
  302. ctx.Handle(404, ctx.Req.RequestURI, nil)
  303. return
  304. }
  305. }
  306. }
  307. // GitHookService checks if repsitory Git hooks service has been enabled.
  308. func GitHookService() macaron.Handler {
  309. return func(ctx *Context) {
  310. if !setting.Service.EnableGitHooks {
  311. ctx.Handle(404, "GitHookService", nil)
  312. return
  313. }
  314. }
  315. }