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.

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