You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

385 lines
11 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  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 repo
  5. import (
  6. "fmt"
  7. "path"
  8. "path/filepath"
  9. "strings"
  10. "github.com/go-martini/martini"
  11. "github.com/gogits/webdav"
  12. "github.com/gogits/gogs/models"
  13. "github.com/gogits/gogs/modules/auth"
  14. "github.com/gogits/gogs/modules/base"
  15. "github.com/gogits/gogs/modules/log"
  16. "github.com/gogits/gogs/modules/middleware"
  17. )
  18. func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
  19. ctx.Data["Title"] = "Create repository"
  20. ctx.Data["PageIsNewRepo"] = true // For navbar arrow.
  21. ctx.Data["LanguageIgns"] = models.LanguageIgns
  22. ctx.Data["Licenses"] = models.Licenses
  23. if ctx.Req.Method == "GET" {
  24. ctx.HTML(200, "repo/create")
  25. return
  26. }
  27. if ctx.HasError() {
  28. ctx.HTML(200, "repo/create")
  29. return
  30. }
  31. _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
  32. form.Language, form.License, form.Visibility == "private", form.InitReadme == "on")
  33. if err == nil {
  34. log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
  35. ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
  36. return
  37. } else if err == models.ErrRepoAlreadyExist {
  38. ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
  39. return
  40. } else if err == models.ErrRepoNameIllegal {
  41. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/create", &form)
  42. return
  43. }
  44. ctx.Handle(200, "repo.Create", err)
  45. }
  46. func Single(ctx *middleware.Context, params martini.Params) {
  47. branchName := ctx.Repo.BranchName
  48. commitId := ctx.Repo.CommitId
  49. userName := ctx.Repo.Owner.Name
  50. repoName := ctx.Repo.Repository.Name
  51. repoLink := ctx.Repo.RepoLink
  52. branchLink := ctx.Repo.RepoLink + "/src/" + branchName
  53. rawLink := ctx.Repo.RepoLink + "/raw/" + branchName
  54. // Get tree path
  55. treename := params["_1"]
  56. if len(treename) > 0 && treename[len(treename)-1] == '/' {
  57. ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1])
  58. return
  59. }
  60. ctx.Data["IsRepoToolbarSource"] = true
  61. // Branches.
  62. brs, err := models.GetBranches(userName, repoName)
  63. if err != nil {
  64. ctx.Handle(404, "repo.Single(GetBranches)", err)
  65. return
  66. }
  67. ctx.Data["Branches"] = brs
  68. isViewBranch := ctx.Repo.IsBranch
  69. ctx.Data["IsViewBranch"] = isViewBranch
  70. repoFile, err := models.GetTargetFile(userName, repoName,
  71. branchName, commitId, treename)
  72. if err != nil && err != models.ErrRepoFileNotExist {
  73. ctx.Handle(404, "repo.Single(GetTargetFile)", err)
  74. return
  75. }
  76. if len(treename) != 0 && repoFile == nil {
  77. ctx.Handle(404, "repo.Single", nil)
  78. return
  79. }
  80. if repoFile != nil && repoFile.IsFile() {
  81. if blob, err := repoFile.LookupBlob(); err != nil {
  82. ctx.Handle(404, "repo.Single(repoFile.LookupBlob)", err)
  83. } else {
  84. ctx.Data["FileSize"] = repoFile.Size
  85. ctx.Data["IsFile"] = true
  86. ctx.Data["FileName"] = repoFile.Name
  87. ext := path.Ext(repoFile.Name)
  88. if len(ext) > 0 {
  89. ext = ext[1:]
  90. }
  91. ctx.Data["FileExt"] = ext
  92. ctx.Data["FileLink"] = rawLink + "/" + treename
  93. data := blob.Contents()
  94. _, isTextFile := base.IsTextFile(data)
  95. _, isImageFile := base.IsImageFile(data)
  96. ctx.Data["FileIsText"] = isTextFile
  97. if isImageFile {
  98. ctx.Data["IsImageFile"] = true
  99. } else {
  100. readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
  101. ctx.Data["ReadmeExist"] = readmeExist
  102. if readmeExist {
  103. ctx.Data["FileContent"] = string(base.RenderMarkdown(data, ""))
  104. } else {
  105. if isTextFile {
  106. ctx.Data["FileContent"] = string(data)
  107. }
  108. }
  109. }
  110. }
  111. } else {
  112. // Directory and file list.
  113. files, err := models.GetReposFiles(userName, repoName, ctx.Repo.CommitId, treename)
  114. if err != nil {
  115. ctx.Handle(404, "repo.Single(GetReposFiles)", err)
  116. return
  117. }
  118. ctx.Data["Files"] = files
  119. var readmeFile *models.RepoFile
  120. for _, f := range files {
  121. if !f.IsFile() || !base.IsReadmeFile(f.Name) {
  122. continue
  123. } else {
  124. readmeFile = f
  125. break
  126. }
  127. }
  128. if readmeFile != nil {
  129. ctx.Data["ReadmeInSingle"] = true
  130. ctx.Data["ReadmeExist"] = true
  131. if blob, err := readmeFile.LookupBlob(); err != nil {
  132. ctx.Handle(404, "repo.Single(readmeFile.LookupBlob)", err)
  133. return
  134. } else {
  135. ctx.Data["FileSize"] = readmeFile.Size
  136. ctx.Data["FileLink"] = rawLink + "/" + treename
  137. data := blob.Contents()
  138. _, isTextFile := base.IsTextFile(data)
  139. ctx.Data["FileIsText"] = isTextFile
  140. ctx.Data["FileName"] = readmeFile.Name
  141. if isTextFile {
  142. ctx.Data["FileContent"] = string(base.RenderMarkdown(data, branchLink))
  143. }
  144. }
  145. }
  146. }
  147. ctx.Data["Username"] = userName
  148. ctx.Data["Reponame"] = repoName
  149. var treenames []string
  150. Paths := make([]string, 0)
  151. if len(treename) > 0 {
  152. treenames = strings.Split(treename, "/")
  153. for i, _ := range treenames {
  154. Paths = append(Paths, strings.Join(treenames[0:i+1], "/"))
  155. }
  156. ctx.Data["HasParentPath"] = true
  157. if len(Paths)-2 >= 0 {
  158. ctx.Data["ParentPath"] = "/" + Paths[len(Paths)-2]
  159. }
  160. }
  161. ctx.Data["LastCommit"] = ctx.Repo.Commit
  162. ctx.Data["Paths"] = Paths
  163. ctx.Data["Treenames"] = treenames
  164. ctx.Data["BranchLink"] = branchLink
  165. ctx.HTML(200, "repo/single")
  166. }
  167. func SingleDownload(ctx *middleware.Context, params martini.Params) {
  168. // Get tree path
  169. treename := params["_1"]
  170. branchName := params["branchname"]
  171. userName := params["username"]
  172. repoName := params["reponame"]
  173. var commitId string
  174. if !models.IsBranchExist(userName, repoName, branchName) {
  175. commitId = branchName
  176. branchName = ""
  177. }
  178. repoFile, err := models.GetTargetFile(userName, repoName,
  179. branchName, commitId, treename)
  180. if err != nil {
  181. ctx.Handle(404, "repo.SingleDownload(GetTargetFile)", err)
  182. return
  183. }
  184. blob, err := repoFile.LookupBlob()
  185. if err != nil {
  186. ctx.Handle(404, "repo.SingleDownload(LookupBlob)", err)
  187. return
  188. }
  189. data := blob.Contents()
  190. contentType, isTextFile := base.IsTextFile(data)
  191. _, isImageFile := base.IsImageFile(data)
  192. ctx.Res.Header().Set("Content-Type", contentType)
  193. if !isTextFile && !isImageFile {
  194. ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(treename))
  195. ctx.Res.Header().Set("Content-Transfer-Encoding", "binary")
  196. }
  197. ctx.Res.Write(data)
  198. }
  199. func Http(ctx *middleware.Context, params martini.Params) {
  200. // TODO: access check
  201. username := params["username"]
  202. reponame := params["reponame"]
  203. if strings.HasSuffix(reponame, ".git") {
  204. reponame = reponame[:len(reponame)-4]
  205. }
  206. dir := models.RepoPath(username, reponame)
  207. prefix := path.Join("/", username, params["reponame"])
  208. server := webdav.NewServer(
  209. dir, prefix, true)
  210. server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
  211. }
  212. func Setting(ctx *middleware.Context, params martini.Params) {
  213. if !ctx.Repo.IsOwner {
  214. ctx.Handle(404, "repo.Setting", nil)
  215. return
  216. }
  217. ctx.Data["IsRepoToolbarSetting"] = true
  218. var title string
  219. if t, ok := ctx.Data["Title"].(string); ok {
  220. title = t
  221. }
  222. ctx.Data["Title"] = title + " - settings"
  223. ctx.HTML(200, "repo/setting")
  224. }
  225. func SettingPost(ctx *middleware.Context) {
  226. if !ctx.Repo.IsOwner {
  227. ctx.Error(404)
  228. return
  229. }
  230. switch ctx.Query("action") {
  231. case "update":
  232. isNameChanged := false
  233. newRepoName := ctx.Query("name")
  234. // Check if repository name has been changed.
  235. if ctx.Repo.Repository.Name != newRepoName {
  236. isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName)
  237. if err != nil {
  238. ctx.Handle(404, "repo.SettingPost(update: check existence)", err)
  239. return
  240. } else if isExist {
  241. ctx.RenderWithErr("Repository name has been taken in your repositories.", "repo/setting", nil)
  242. return
  243. } else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
  244. ctx.Handle(404, "repo.SettingPost(change repository name)", err)
  245. return
  246. }
  247. log.Trace("%s Repository name changed: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newRepoName)
  248. isNameChanged = true
  249. ctx.Repo.Repository.Name = newRepoName
  250. }
  251. ctx.Repo.Repository.Description = ctx.Query("desc")
  252. ctx.Repo.Repository.Website = ctx.Query("site")
  253. if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
  254. ctx.Handle(404, "repo.SettingPost(update)", err)
  255. return
  256. }
  257. ctx.Data["IsSuccess"] = true
  258. if isNameChanged {
  259. ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
  260. } else {
  261. ctx.HTML(200, "repo/setting")
  262. }
  263. log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
  264. case "transfer":
  265. if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
  266. ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil)
  267. return
  268. }
  269. newOwner := ctx.Query("owner")
  270. // Check if new owner exists.
  271. isExist, err := models.IsUserExist(newOwner)
  272. if err != nil {
  273. ctx.Handle(404, "repo.SettingPost(transfer: check existence)", err)
  274. return
  275. } else if !isExist {
  276. ctx.RenderWithErr("Please make sure you entered owner name is correct.", "repo/setting", nil)
  277. return
  278. } else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
  279. ctx.Handle(404, "repo.SettingPost(transfer repository)", err)
  280. return
  281. }
  282. log.Trace("%s Repository transfered: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newOwner)
  283. ctx.Redirect("/")
  284. return
  285. case "delete":
  286. if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
  287. ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil)
  288. return
  289. }
  290. if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil {
  291. ctx.Handle(200, "repo.Delete", err)
  292. return
  293. }
  294. log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
  295. ctx.Redirect("/")
  296. }
  297. }
  298. func Action(ctx *middleware.Context, params martini.Params) {
  299. var err error
  300. switch params["action"] {
  301. case "watch":
  302. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  303. case "unwatch":
  304. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  305. case "desc":
  306. if !ctx.Repo.IsOwner {
  307. ctx.Error(404)
  308. return
  309. }
  310. ctx.Repo.Repository.Description = ctx.Query("desc")
  311. ctx.Repo.Repository.Website = ctx.Query("site")
  312. err = models.UpdateRepository(ctx.Repo.Repository)
  313. }
  314. if err != nil {
  315. log.Error("repo.Action(%s): %v", params["action"], err)
  316. ctx.JSON(200, map[string]interface{}{
  317. "ok": false,
  318. "err": err.Error(),
  319. })
  320. return
  321. }
  322. ctx.JSON(200, map[string]interface{}{
  323. "ok": true,
  324. })
  325. }