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 10 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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. // Non-fork repository will not return error in this method.
  258. if err = repo.GetForkRepo(); err != nil {
  259. ctx.Handle(500, "GetForkRepo", err)
  260. return
  261. }
  262. ctx.Data["Title"] = u.Name + "/" + repo.Name
  263. ctx.Data["Repository"] = repo
  264. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  265. ctx.Data["IsRepositoryOwner"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_WRITE
  266. ctx.Data["IsRepositoryAdmin"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_ADMIN
  267. ctx.Data["DisableSSH"] = setting.DisableSSH
  268. ctx.Repo.CloneLink, err = repo.CloneLink()
  269. if err != nil {
  270. ctx.Handle(500, "CloneLink", err)
  271. return
  272. }
  273. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  274. if ctx.Query("go-get") == "1" {
  275. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
  276. }
  277. // repo is bare and display enable
  278. if ctx.Repo.Repository.IsBare {
  279. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  280. // NOTE: to prevent templating error
  281. ctx.Data["BranchName"] = ""
  282. if displayBare {
  283. ctx.HTML(200, "repo/bare")
  284. }
  285. return
  286. }
  287. if ctx.IsSigned {
  288. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id)
  289. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id)
  290. }
  291. ctx.Data["TagName"] = ctx.Repo.TagName
  292. brs, err := ctx.Repo.GitRepo.GetBranches()
  293. if err != nil {
  294. ctx.Handle(500, "GetBranches", err)
  295. return
  296. }
  297. ctx.Data["Branches"] = brs
  298. ctx.Data["BrancheCount"] = len(brs)
  299. // If not branch selected, try default one.
  300. // If default branch doesn't exists, fall back to some other branch.
  301. if ctx.Repo.BranchName == "" {
  302. if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  303. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  304. } else if len(brs) > 0 {
  305. ctx.Repo.BranchName = brs[0]
  306. }
  307. }
  308. ctx.Data["BranchName"] = ctx.Repo.BranchName
  309. ctx.Data["CommitId"] = ctx.Repo.CommitId
  310. userAgent := ctx.Req.Header.Get("User-Agent")
  311. ua := user_agent.New(userAgent)
  312. browserName, browserVer := ua.Browser()
  313. ctx.Data["BrowserSupportsCopy"] = (browserName == "Chrome" && version.Compare(browserVer, CHROME_COPY_SUPPORT, ">=")) ||
  314. (browserName == "Firefox" && version.Compare(browserVer, FIREFOX_COPY_SUPPORT, ">="))
  315. }
  316. }
  317. func RequireRepoAdmin() macaron.Handler {
  318. return func(ctx *Context) {
  319. if ctx.Repo.AccessMode < models.ACCESS_MODE_ADMIN {
  320. if !ctx.IsSigned {
  321. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  322. ctx.Redirect(setting.AppSubUrl + "/user/login")
  323. return
  324. }
  325. ctx.Handle(404, ctx.Req.RequestURI, nil)
  326. return
  327. }
  328. }
  329. }
  330. // GitHookService checks if repository Git hooks service has been enabled.
  331. func GitHookService() macaron.Handler {
  332. return func(ctx *Context) {
  333. if !ctx.User.AllowGitHook && !ctx.User.IsAdmin {
  334. ctx.Handle(404, "GitHookService", nil)
  335. return
  336. }
  337. }
  338. }