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.

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