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
11 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
11 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
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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 err == models.ErrRepoNotExist {
  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. if ctx.IsSigned {
  53. mode, err := models.AccessLevel(ctx.User, repo)
  54. if err != nil {
  55. ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL})
  56. return
  57. }
  58. ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE
  59. ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ
  60. ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER
  61. }
  62. // Check access.
  63. if repo.IsPrivate && !ctx.Repo.IsOwner {
  64. ctx.Error(404)
  65. return
  66. }
  67. ctx.Repo.HasAccess = true
  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 RepoAssignment(redirect bool, args ...bool) macaron.Handler {
  168. return func(ctx *Context) {
  169. var (
  170. displayBare bool // To display bare page if it is a bare repo.
  171. )
  172. if len(args) >= 1 {
  173. displayBare = args[0]
  174. }
  175. var (
  176. u *models.User
  177. err error
  178. )
  179. userName := ctx.Params(":username")
  180. repoName := ctx.Params(":reponame")
  181. refName := ctx.Params(":branchname")
  182. if len(refName) == 0 {
  183. refName = ctx.Params(":path")
  184. }
  185. // Check if the user is the same as the repository owner
  186. if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
  187. u = ctx.User
  188. } else {
  189. u, err = models.GetUserByName(userName)
  190. if err != nil {
  191. if err == models.ErrUserNotExist {
  192. ctx.Handle(404, "GetUserByName", err)
  193. } else {
  194. ctx.Handle(500, "GetUserByName", err)
  195. }
  196. return
  197. }
  198. }
  199. ctx.Repo.Owner = u
  200. // Get repository.
  201. repo, err := models.GetRepositoryByName(u.Id, repoName)
  202. if err != nil {
  203. if err == models.ErrRepoNotExist {
  204. ctx.Handle(404, "GetRepositoryByName", err)
  205. } else {
  206. ctx.Handle(500, "GetRepositoryByName", err)
  207. }
  208. return
  209. } else if err = repo.GetOwner(); err != nil {
  210. ctx.Handle(500, "GetOwner", err)
  211. return
  212. }
  213. if ctx.IsSigned {
  214. mode, err := models.AccessLevel(ctx.User, repo)
  215. if err != nil {
  216. ctx.Handle(500, "AccessLevel", err)
  217. return
  218. }
  219. ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE
  220. ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ
  221. ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER
  222. if !ctx.Repo.IsTrueOwner && ctx.Repo.Owner.IsOrganization() {
  223. ctx.Repo.IsTrueOwner = ctx.Repo.Owner.IsOwnedBy(ctx.User.Id)
  224. }
  225. }
  226. // Check access.
  227. if repo.IsPrivate && !ctx.Repo.IsOwner {
  228. ctx.Handle(404, "no access right", err)
  229. return
  230. }
  231. ctx.Repo.HasAccess = true
  232. ctx.Data["HasAccess"] = true
  233. if repo.IsMirror {
  234. ctx.Repo.Mirror, err = models.GetMirror(repo.Id)
  235. if err != nil {
  236. ctx.Handle(500, "GetMirror", err)
  237. return
  238. }
  239. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  240. }
  241. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  242. repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
  243. ctx.Repo.Repository = repo
  244. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  245. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  246. if err != nil {
  247. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  248. return
  249. }
  250. ctx.Repo.GitRepo = gitRepo
  251. ctx.Repo.RepoLink, err = repo.RepoLink()
  252. if err != nil {
  253. ctx.Handle(500, "RepoLink", err)
  254. return
  255. }
  256. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  257. tags, err := ctx.Repo.GitRepo.GetTags()
  258. if err != nil {
  259. ctx.Handle(500, "GetTags", err)
  260. return
  261. }
  262. ctx.Data["Tags"] = tags
  263. ctx.Repo.Repository.NumTags = len(tags)
  264. // Non-fork repository will not return error in this method.
  265. if err = repo.GetForkRepo(); err != nil {
  266. ctx.Handle(500, "GetForkRepo", err)
  267. return
  268. }
  269. ctx.Data["Title"] = u.Name + "/" + repo.Name
  270. ctx.Data["Repository"] = repo
  271. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  272. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
  273. ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner
  274. ctx.Data["DisableSSH"] = setting.DisableSSH
  275. ctx.Repo.CloneLink, err = repo.CloneLink()
  276. if err != nil {
  277. ctx.Handle(500, "CloneLink", err)
  278. return
  279. }
  280. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  281. if ctx.Query("go-get") == "1" {
  282. ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
  283. }
  284. // repo is bare and display enable
  285. if ctx.Repo.Repository.IsBare {
  286. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  287. // NOTE: to prevent templating error
  288. ctx.Data["BranchName"] = ""
  289. if displayBare {
  290. ctx.HTML(200, "repo/bare")
  291. }
  292. return
  293. }
  294. if ctx.IsSigned {
  295. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id)
  296. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id)
  297. }
  298. ctx.Data["TagName"] = ctx.Repo.TagName
  299. brs, err := ctx.Repo.GitRepo.GetBranches()
  300. if err != nil {
  301. ctx.Handle(500, "GetBranches", err)
  302. return
  303. }
  304. ctx.Data["Branches"] = brs
  305. ctx.Data["BrancheCount"] = len(brs)
  306. // If not branch selected, try default one.
  307. // If default branch doesn't exists, fall back to some other branch.
  308. if ctx.Repo.BranchName == "" {
  309. if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  310. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  311. } else if len(brs) > 0 {
  312. ctx.Repo.BranchName = brs[0]
  313. }
  314. }
  315. ctx.Data["BranchName"] = ctx.Repo.BranchName
  316. ctx.Data["CommitId"] = ctx.Repo.CommitId
  317. }
  318. }
  319. func RequireTrueOwner() macaron.Handler {
  320. return func(ctx *Context) {
  321. if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin {
  322. if !ctx.IsSigned {
  323. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  324. ctx.Redirect(setting.AppSubUrl + "/user/login")
  325. return
  326. }
  327. ctx.Handle(404, ctx.Req.RequestURI, nil)
  328. return
  329. }
  330. }
  331. }
  332. // GitHookService checks if repository Git hooks service has been enabled.
  333. func GitHookService() macaron.Handler {
  334. return func(ctx *Context) {
  335. if !ctx.User.AllowGitHook && !ctx.User.IsAdmin {
  336. ctx.Handle(404, "GitHookService", nil)
  337. return
  338. }
  339. }
  340. }