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.

387 lines
10 KiB

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