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