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

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 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
9 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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 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. u *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. u = ctx.User
  222. } else {
  223. u, 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 = u
  234. // Get repository.
  235. repo, err := models.GetRepositoryByName(u.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. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  268. repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
  269. ctx.Repo.Repository = repo
  270. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  271. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  272. if err != nil {
  273. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  274. return
  275. }
  276. ctx.Repo.GitRepo = gitRepo
  277. ctx.Repo.RepoLink, err = repo.RepoLink()
  278. if err != nil {
  279. ctx.Handle(500, "RepoLink", err)
  280. return
  281. }
  282. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  283. ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
  284. tags, err := ctx.Repo.GitRepo.GetTags()
  285. if err != nil {
  286. ctx.Handle(500, "GetTags", err)
  287. return
  288. }
  289. ctx.Data["Tags"] = tags
  290. ctx.Repo.Repository.NumTags = len(tags)
  291. if repo.IsFork {
  292. RetrieveBaseRepo(ctx, repo)
  293. if ctx.Written() {
  294. return
  295. }
  296. }
  297. ctx.Data["Title"] = u.Name + "/" + repo.Name
  298. ctx.Data["Repository"] = repo
  299. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  300. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
  301. ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
  302. ctx.Data["DisableSSH"] = setting.DisableSSH
  303. ctx.Repo.CloneLink, err = repo.CloneLink()
  304. if err != nil {
  305. ctx.Handle(500, "CloneLink", err)
  306. return
  307. }
  308. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  309. if ctx.Query("go-get") == "1" {
  310. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
  311. }
  312. // repo is bare and display enable
  313. if ctx.Repo.Repository.IsBare {
  314. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  315. // NOTE: to prevent templating error
  316. ctx.Data["BranchName"] = ""
  317. if displayBare {
  318. ctx.HTML(200, "repo/bare")
  319. }
  320. return
  321. }
  322. if ctx.IsSigned {
  323. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
  324. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
  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. }