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.

424 lines
11 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 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
9 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/mcuadros/go-version"
  10. "github.com/mssola/user_agent"
  11. "gopkg.in/macaron.v1"
  12. "github.com/gogits/gogs/models"
  13. "github.com/gogits/gogs/modules/git"
  14. "github.com/gogits/gogs/modules/log"
  15. "github.com/gogits/gogs/modules/setting"
  16. )
  17. const (
  18. FIREFOX_COPY_SUPPORT = "41.0"
  19. CHROME_COPY_SUPPORT = "43.0.2356"
  20. )
  21. func ApiRepoAssignment() macaron.Handler {
  22. return func(ctx *Context) {
  23. userName := ctx.Params(":username")
  24. repoName := ctx.Params(":reponame")
  25. var (
  26. u *models.User
  27. err error
  28. )
  29. // Check if the user is the same as the repository owner.
  30. if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
  31. u = ctx.User
  32. } else {
  33. u, err = models.GetUserByName(userName)
  34. if err != nil {
  35. if models.IsErrUserNotExist(err) {
  36. ctx.Error(404)
  37. } else {
  38. ctx.APIError(500, "GetUserByName", err)
  39. }
  40. return
  41. }
  42. }
  43. ctx.Repo.Owner = u
  44. // Get repository.
  45. repo, err := models.GetRepositoryByName(u.Id, repoName)
  46. if err != nil {
  47. if models.IsErrRepoNotExist(err) {
  48. ctx.Error(404)
  49. } else {
  50. ctx.APIError(500, "GetRepositoryByName", err)
  51. }
  52. return
  53. } else if err = repo.GetOwner(); err != nil {
  54. ctx.APIError(500, "GetOwner", err)
  55. return
  56. }
  57. mode, err := models.AccessLevel(ctx.User, repo)
  58. if err != nil {
  59. ctx.APIError(500, "AccessLevel", err)
  60. return
  61. }
  62. ctx.Repo.AccessMode = mode
  63. // Check access.
  64. if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
  65. ctx.Error(404)
  66. return
  67. }
  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 RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
  168. // Non-fork repository will not return error in this method.
  169. if err := repo.GetBaseRepo(); err != nil {
  170. if models.IsErrRepoNotExist(err) {
  171. repo.IsFork = false
  172. repo.ForkID = 0
  173. return
  174. }
  175. ctx.Handle(500, "GetBaseRepo", err)
  176. return
  177. } else if err = repo.BaseRepo.GetOwner(); err != nil {
  178. ctx.Handle(500, "BaseRepo.GetOwner", err)
  179. return
  180. }
  181. bsaeRepo := repo.BaseRepo
  182. baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name))
  183. if err != nil {
  184. ctx.Handle(500, "OpenRepository", err)
  185. return
  186. }
  187. if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) {
  188. ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch
  189. } else {
  190. baseBranches, err := baseGitRepo.GetBranches()
  191. if err != nil {
  192. ctx.Handle(500, "GetBranches", err)
  193. return
  194. }
  195. if len(baseBranches) > 0 {
  196. ctx.Data["BaseDefaultBranch"] = baseBranches[0]
  197. }
  198. }
  199. }
  200. func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
  201. return func(ctx *Context) {
  202. var (
  203. displayBare bool // To display bare page if it is a bare repo.
  204. )
  205. if len(args) >= 1 {
  206. displayBare = args[0]
  207. }
  208. var (
  209. u *models.User
  210. err error
  211. )
  212. userName := ctx.Params(":username")
  213. repoName := ctx.Params(":reponame")
  214. refName := ctx.Params(":branchname")
  215. if len(refName) == 0 {
  216. refName = ctx.Params(":path")
  217. }
  218. // Check if the user is the same as the repository owner
  219. if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
  220. u = ctx.User
  221. } else {
  222. u, err = models.GetUserByName(userName)
  223. if err != nil {
  224. if models.IsErrUserNotExist(err) {
  225. ctx.Handle(404, "GetUserByName", err)
  226. } else {
  227. ctx.Handle(500, "GetUserByName", err)
  228. }
  229. return
  230. }
  231. }
  232. ctx.Repo.Owner = u
  233. // Get repository.
  234. repo, err := models.GetRepositoryByName(u.Id, repoName)
  235. if err != nil {
  236. if models.IsErrRepoNotExist(err) {
  237. ctx.Handle(404, "GetRepositoryByName", err)
  238. } else {
  239. ctx.Handle(500, "GetRepositoryByName", err)
  240. }
  241. return
  242. } else if err = repo.GetOwner(); err != nil {
  243. ctx.Handle(500, "GetOwner", err)
  244. return
  245. }
  246. mode, err := models.AccessLevel(ctx.User, repo)
  247. if err != nil {
  248. ctx.Handle(500, "AccessLevel", err)
  249. return
  250. }
  251. ctx.Repo.AccessMode = mode
  252. // Check access.
  253. if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
  254. ctx.Handle(404, "no access right", err)
  255. return
  256. }
  257. ctx.Data["HasAccess"] = true
  258. if repo.IsMirror {
  259. ctx.Repo.Mirror, err = models.GetMirror(repo.ID)
  260. if err != nil {
  261. ctx.Handle(500, "GetMirror", err)
  262. return
  263. }
  264. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  265. }
  266. ctx.Repo.Repository = repo
  267. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  268. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  269. if err != nil {
  270. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  271. return
  272. }
  273. ctx.Repo.GitRepo = gitRepo
  274. ctx.Repo.RepoLink, err = repo.RepoLink()
  275. if err != nil {
  276. ctx.Handle(500, "RepoLink", err)
  277. return
  278. }
  279. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  280. ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
  281. tags, err := ctx.Repo.GitRepo.GetTags()
  282. if err != nil {
  283. ctx.Handle(500, "GetTags", err)
  284. return
  285. }
  286. ctx.Data["Tags"] = tags
  287. ctx.Repo.Repository.NumTags = len(tags)
  288. if repo.IsFork {
  289. RetrieveBaseRepo(ctx, repo)
  290. if ctx.Written() {
  291. return
  292. }
  293. }
  294. ctx.Data["Title"] = u.Name + "/" + repo.Name
  295. ctx.Data["Repository"] = repo
  296. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  297. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
  298. ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
  299. ctx.Data["DisableSSH"] = setting.DisableSSH
  300. ctx.Repo.CloneLink, err = repo.CloneLink()
  301. if err != nil {
  302. ctx.Handle(500, "CloneLink", err)
  303. return
  304. }
  305. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  306. if ctx.Query("go-get") == "1" {
  307. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.Name, repo.Name)
  308. }
  309. if ctx.IsSigned {
  310. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
  311. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
  312. }
  313. // repo is bare and display enable
  314. if ctx.Repo.Repository.IsBare {
  315. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  316. // NOTE: to prevent templating error
  317. ctx.Data["BranchName"] = ""
  318. if displayBare {
  319. if !ctx.Repo.IsAdmin() {
  320. ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
  321. }
  322. ctx.HTML(200, "repo/bare")
  323. }
  324. return
  325. }
  326. ctx.Data["TagName"] = ctx.Repo.TagName
  327. brs, err := ctx.Repo.GitRepo.GetBranches()
  328. if err != nil {
  329. ctx.Handle(500, "GetBranches", err)
  330. return
  331. }
  332. ctx.Data["Branches"] = brs
  333. ctx.Data["BrancheCount"] = len(brs)
  334. // If not branch selected, try default one.
  335. // If default branch doesn't exists, fall back to some other branch.
  336. if len(ctx.Repo.BranchName) == 0 {
  337. if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  338. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  339. } else if len(brs) > 0 {
  340. ctx.Repo.BranchName = brs[0]
  341. }
  342. }
  343. ctx.Data["BranchName"] = ctx.Repo.BranchName
  344. ctx.Data["CommitID"] = ctx.Repo.CommitID
  345. userAgent := ctx.Req.Header.Get("User-Agent")
  346. ua := user_agent.New(userAgent)
  347. browserName, browserVer := ua.Browser()
  348. ctx.Data["BrowserSupportsCopy"] = (browserName == "Chrome" && version.Compare(browserVer, CHROME_COPY_SUPPORT, ">=")) ||
  349. (browserName == "Firefox" && version.Compare(browserVer, FIREFOX_COPY_SUPPORT, ">="))
  350. }
  351. }
  352. func RequireRepoAdmin() macaron.Handler {
  353. return func(ctx *Context) {
  354. if !ctx.Repo.IsAdmin() {
  355. if !ctx.IsSigned {
  356. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  357. ctx.Redirect(setting.AppSubUrl + "/user/login")
  358. return
  359. }
  360. ctx.Handle(404, ctx.Req.RequestURI, nil)
  361. return
  362. }
  363. }
  364. }
  365. // GitHookService checks if repository Git hooks service has been enabled.
  366. func GitHookService() macaron.Handler {
  367. return func(ctx *Context) {
  368. if !ctx.User.AllowGitHook && !ctx.User.IsAdmin {
  369. ctx.Handle(404, "GitHookService", nil)
  370. return
  371. }
  372. }
  373. }