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
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. "gopkg.in/macaron.v1"
  11. "github.com/gogits/gogs/models"
  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. owner *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. owner = ctx.User
  27. } else {
  28. owner, err = models.GetUserByName(userName)
  29. if err != nil {
  30. if models.IsErrUserNotExist(err) {
  31. ctx.Error(404)
  32. } else {
  33. ctx.APIError(500, "GetUserByName", err)
  34. }
  35. return
  36. }
  37. }
  38. ctx.Repo.Owner = owner
  39. // Get repository.
  40. repo, err := models.GetRepositoryByName(owner.Id, repoName)
  41. if err != nil {
  42. if models.IsErrRepoNotExist(err) {
  43. ctx.Error(404)
  44. } else {
  45. ctx.APIError(500, "GetRepositoryByName", err)
  46. }
  47. return
  48. } else if err = repo.GetOwner(); err != nil {
  49. ctx.APIError(500, "GetOwner", err)
  50. return
  51. }
  52. mode, err := models.AccessLevel(ctx.User, repo)
  53. if err != nil {
  54. ctx.APIError(500, "AccessLevel", err)
  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. // Empty repository does not have reference information.
  70. if ctx.Repo.Repository.IsBare {
  71. return
  72. }
  73. var (
  74. refName string
  75. err error
  76. )
  77. // For API calls.
  78. if ctx.Repo.GitRepo == nil {
  79. repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
  80. gitRepo, err := git.OpenRepository(repoPath)
  81. if err != nil {
  82. ctx.Handle(500, "RepoRef Invalid repo "+repoPath, err)
  83. return
  84. }
  85. ctx.Repo.GitRepo = gitRepo
  86. }
  87. // Get default branch.
  88. if len(ctx.Params("*")) == 0 {
  89. refName = ctx.Repo.Repository.DefaultBranch
  90. if !ctx.Repo.GitRepo.IsBranchExist(refName) {
  91. brs, err := ctx.Repo.GitRepo.GetBranches()
  92. if err != nil {
  93. ctx.Handle(500, "GetBranches", err)
  94. return
  95. }
  96. refName = brs[0]
  97. }
  98. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  99. if err != nil {
  100. ctx.Handle(500, "GetCommitOfBranch", err)
  101. return
  102. }
  103. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  104. ctx.Repo.IsBranch = true
  105. } else {
  106. hasMatched := false
  107. parts := strings.Split(ctx.Params("*"), "/")
  108. for i, part := range parts {
  109. refName = strings.TrimPrefix(refName+"/"+part, "/")
  110. if ctx.Repo.GitRepo.IsBranchExist(refName) ||
  111. ctx.Repo.GitRepo.IsTagExist(refName) {
  112. if i < len(parts)-1 {
  113. ctx.Repo.TreeName = strings.Join(parts[i+1:], "/")
  114. }
  115. hasMatched = true
  116. break
  117. }
  118. }
  119. if !hasMatched && len(parts[0]) == 40 {
  120. refName = parts[0]
  121. ctx.Repo.TreeName = strings.Join(parts[1:], "/")
  122. }
  123. if ctx.Repo.GitRepo.IsBranchExist(refName) {
  124. ctx.Repo.IsBranch = true
  125. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName)
  126. if err != nil {
  127. ctx.Handle(500, "GetCommitOfBranch", err)
  128. return
  129. }
  130. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  131. } else if ctx.Repo.GitRepo.IsTagExist(refName) {
  132. ctx.Repo.IsTag = true
  133. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfTag(refName)
  134. if err != nil {
  135. ctx.Handle(500, "GetCommitOfTag", err)
  136. return
  137. }
  138. ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
  139. } else if len(refName) == 40 {
  140. ctx.Repo.IsCommit = true
  141. ctx.Repo.CommitID = refName
  142. ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
  143. if err != nil {
  144. ctx.Handle(404, "GetCommit", nil)
  145. return
  146. }
  147. } else {
  148. ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
  149. return
  150. }
  151. }
  152. ctx.Repo.BranchName = refName
  153. ctx.Data["BranchName"] = ctx.Repo.BranchName
  154. ctx.Data["CommitID"] = ctx.Repo.CommitID
  155. ctx.Data["IsBranch"] = ctx.Repo.IsBranch
  156. ctx.Data["IsTag"] = ctx.Repo.IsTag
  157. ctx.Data["IsCommit"] = ctx.Repo.IsCommit
  158. ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
  159. if err != nil {
  160. ctx.Handle(500, "CommitsCount", err)
  161. return
  162. }
  163. ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
  164. }
  165. }
  166. func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
  167. // Non-fork repository will not return error in this method.
  168. if err := repo.GetBaseRepo(); err != nil {
  169. if models.IsErrRepoNotExist(err) {
  170. repo.IsFork = false
  171. repo.ForkID = 0
  172. return
  173. }
  174. ctx.Handle(500, "GetBaseRepo", err)
  175. return
  176. } else if err = repo.BaseRepo.GetOwner(); err != nil {
  177. ctx.Handle(500, "BaseRepo.GetOwner", err)
  178. return
  179. }
  180. bsaeRepo := repo.BaseRepo
  181. baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name))
  182. if err != nil {
  183. ctx.Handle(500, "OpenRepository", err)
  184. return
  185. }
  186. if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) {
  187. ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch
  188. } else {
  189. baseBranches, err := baseGitRepo.GetBranches()
  190. if err != nil {
  191. ctx.Handle(500, "GetBranches", err)
  192. return
  193. }
  194. if len(baseBranches) > 0 {
  195. ctx.Data["BaseDefaultBranch"] = baseBranches[0]
  196. }
  197. }
  198. }
  199. func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
  200. return func(ctx *Context) {
  201. var (
  202. displayBare bool // To display bare page if it is a bare repo.
  203. )
  204. if len(args) >= 1 {
  205. displayBare = args[0]
  206. }
  207. var (
  208. owner *models.User
  209. err error
  210. )
  211. userName := ctx.Params(":username")
  212. repoName := ctx.Params(":reponame")
  213. refName := ctx.Params(":branchname")
  214. if len(refName) == 0 {
  215. refName = ctx.Params(":path")
  216. }
  217. // Check if the user is the same as the repository owner
  218. if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
  219. owner = ctx.User
  220. } else {
  221. owner, err = models.GetUserByName(userName)
  222. if err != nil {
  223. if models.IsErrUserNotExist(err) {
  224. ctx.Handle(404, "GetUserByName", err)
  225. } else {
  226. ctx.Handle(500, "GetUserByName", err)
  227. }
  228. return
  229. }
  230. }
  231. ctx.Repo.Owner = owner
  232. // Get repository.
  233. repo, err := models.GetRepositoryByName(owner.Id, repoName)
  234. if err != nil {
  235. if models.IsErrRepoNotExist(err) {
  236. ctx.Handle(404, "GetRepositoryByName", err)
  237. } else {
  238. ctx.Handle(500, "GetRepositoryByName", err)
  239. }
  240. return
  241. } else if err = repo.GetOwner(); err != nil {
  242. ctx.Handle(500, "GetOwner", err)
  243. return
  244. }
  245. // Admin has super access.
  246. if ctx.IsSigned && ctx.User.IsAdmin {
  247. ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
  248. } else {
  249. mode, err := models.AccessLevel(ctx.User, repo)
  250. if err != nil {
  251. ctx.Handle(500, "AccessLevel", err)
  252. return
  253. }
  254. ctx.Repo.AccessMode = mode
  255. }
  256. // Check access.
  257. if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
  258. ctx.Handle(404, "no access right", err)
  259. return
  260. }
  261. ctx.Data["HasAccess"] = true
  262. if repo.IsMirror {
  263. ctx.Repo.Mirror, err = models.GetMirror(repo.ID)
  264. if err != nil {
  265. ctx.Handle(500, "GetMirror", err)
  266. return
  267. }
  268. ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
  269. }
  270. ctx.Repo.Repository = repo
  271. ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
  272. gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
  273. if err != nil {
  274. ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
  275. return
  276. }
  277. ctx.Repo.GitRepo = gitRepo
  278. ctx.Repo.RepoLink, err = repo.RepoLink()
  279. if err != nil {
  280. ctx.Handle(500, "RepoLink", err)
  281. return
  282. }
  283. ctx.Data["RepoLink"] = ctx.Repo.RepoLink
  284. ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
  285. tags, err := ctx.Repo.GitRepo.GetTags()
  286. if err != nil {
  287. ctx.Handle(500, "GetTags", err)
  288. return
  289. }
  290. ctx.Data["Tags"] = tags
  291. ctx.Repo.Repository.NumTags = len(tags)
  292. if repo.IsFork {
  293. RetrieveBaseRepo(ctx, repo)
  294. if ctx.Written() {
  295. return
  296. }
  297. }
  298. ctx.Data["Title"] = owner.Name + "/" + repo.Name
  299. ctx.Data["Repository"] = repo
  300. ctx.Data["Owner"] = ctx.Repo.Repository.Owner
  301. ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
  302. ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
  303. ctx.Data["DisableSSH"] = setting.DisableSSH
  304. ctx.Repo.CloneLink, err = repo.CloneLink()
  305. if err != nil {
  306. ctx.Handle(500, "CloneLink", err)
  307. return
  308. }
  309. ctx.Data["CloneLink"] = ctx.Repo.CloneLink
  310. if ctx.IsSigned {
  311. ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID)
  312. ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID)
  313. }
  314. // repo is bare and display enable
  315. if ctx.Repo.Repository.IsBare {
  316. log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
  317. // NOTE: to prevent templating error
  318. ctx.Data["BranchName"] = ""
  319. if displayBare {
  320. if !ctx.Repo.IsAdmin() {
  321. ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true)
  322. }
  323. ctx.HTML(200, "repo/bare")
  324. }
  325. return
  326. }
  327. ctx.Data["TagName"] = ctx.Repo.TagName
  328. brs, err := ctx.Repo.GitRepo.GetBranches()
  329. if err != nil {
  330. ctx.Handle(500, "GetBranches", err)
  331. return
  332. }
  333. ctx.Data["Branches"] = brs
  334. ctx.Data["BrancheCount"] = len(brs)
  335. // If not branch selected, try default one.
  336. // If default branch doesn't exists, fall back to some other branch.
  337. if len(ctx.Repo.BranchName) == 0 {
  338. if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
  339. ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
  340. } else if len(brs) > 0 {
  341. ctx.Repo.BranchName = brs[0]
  342. }
  343. }
  344. ctx.Data["BranchName"] = ctx.Repo.BranchName
  345. ctx.Data["CommitID"] = ctx.Repo.CommitID
  346. if ctx.Query("go-get") == "1" {
  347. ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name)
  348. prefix := path.Join(setting.AppUrl, owner.Name, repo.Name, "src", ctx.Repo.BranchName)
  349. ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
  350. ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
  351. }
  352. }
  353. }
  354. func RequireRepoAdmin() macaron.Handler {
  355. return func(ctx *Context) {
  356. if !ctx.Repo.IsAdmin() {
  357. if !ctx.IsSigned {
  358. ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
  359. ctx.Redirect(setting.AppSubUrl + "/user/login")
  360. return
  361. }
  362. ctx.Handle(404, ctx.Req.RequestURI, nil)
  363. return
  364. }
  365. }
  366. }
  367. // GitHookService checks if repository Git hooks service has been enabled.
  368. func GitHookService() macaron.Handler {
  369. return func(ctx *Context) {
  370. if !ctx.User.CanEditGitHook() {
  371. ctx.Handle(404, "GitHookService", nil)
  372. return
  373. }
  374. }
  375. }