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.

433 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
  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. "bytes"
  7. "encoding/base64"
  8. "errors"
  9. "fmt"
  10. "io/ioutil"
  11. "path"
  12. "path/filepath"
  13. "strings"
  14. "github.com/go-martini/martini"
  15. "github.com/gogits/git"
  16. "github.com/gogits/gogs/models"
  17. "github.com/gogits/gogs/modules/auth"
  18. "github.com/gogits/gogs/modules/base"
  19. "github.com/gogits/gogs/modules/log"
  20. "github.com/gogits/gogs/modules/middleware"
  21. )
  22. const (
  23. CREATE base.TplName = "repo/create"
  24. MIGRATE base.TplName = "repo/migrate"
  25. SINGLE base.TplName = "repo/single"
  26. )
  27. func Create(ctx *middleware.Context) {
  28. ctx.Data["Title"] = "Create repository"
  29. ctx.Data["PageIsNewRepo"] = true
  30. ctx.Data["LanguageIgns"] = models.LanguageIgns
  31. ctx.Data["Licenses"] = models.Licenses
  32. ctxUser := ctx.User
  33. orgId, _ := base.StrTo(ctx.Query("org")).Int64()
  34. if orgId > 0 {
  35. org, err := models.GetUserById(orgId)
  36. if err != nil && err != models.ErrUserNotExist {
  37. ctx.Handle(500, "home.Dashboard(GetUserById)", err)
  38. return
  39. }
  40. ctxUser = org
  41. }
  42. ctx.Data["ContextUser"] = ctxUser
  43. if err := ctx.User.GetOrganizations(); err != nil {
  44. ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
  45. return
  46. }
  47. ctx.Data["AllUsers"] = append([]*models.User{ctx.User}, ctx.User.Orgs...)
  48. ctx.HTML(200, CREATE)
  49. }
  50. func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
  51. ctx.Data["Title"] = "Create repository"
  52. ctx.Data["PageIsNewRepo"] = true
  53. ctx.Data["LanguageIgns"] = models.LanguageIgns
  54. ctx.Data["Licenses"] = models.Licenses
  55. if err := ctx.User.GetOrganizations(); err != nil {
  56. ctx.Handle(500, "home.CreatePost(GetOrganizations)", err)
  57. return
  58. }
  59. ctx.Data["Orgs"] = ctx.User.Orgs
  60. if ctx.HasError() {
  61. ctx.HTML(200, CREATE)
  62. return
  63. }
  64. u := ctx.User
  65. // Not equal means current user is an organization.
  66. if u.Id != form.Uid {
  67. var err error
  68. u, err = models.GetUserById(form.Uid)
  69. if err != nil {
  70. if err == models.ErrUserNotExist {
  71. ctx.Handle(404, "home.CreatePost(GetUserById)", err)
  72. } else {
  73. ctx.Handle(500, "home.CreatePost(GetUserById)", err)
  74. }
  75. return
  76. }
  77. // Check ownership of organization.
  78. if !u.IsOrgOwner(ctx.User.Id) {
  79. ctx.Error(403)
  80. return
  81. }
  82. }
  83. repo, err := models.CreateRepository(u, form.RepoName, form.Description,
  84. form.Language, form.License, form.Private, false, form.InitReadme)
  85. if err == nil {
  86. log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName)
  87. ctx.Redirect("/" + u.Name + "/" + form.RepoName)
  88. return
  89. } else if err == models.ErrRepoAlreadyExist {
  90. ctx.RenderWithErr("Repository name has already been used", CREATE, &form)
  91. return
  92. } else if err == models.ErrRepoNameIllegal {
  93. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), CREATE, &form)
  94. return
  95. }
  96. if repo != nil {
  97. if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
  98. log.Error("repo.CreatePost(DeleteRepository): %v", errDelete)
  99. }
  100. }
  101. ctx.Handle(500, "repo.CreatePost(CreateRepository)", err)
  102. }
  103. func Migrate(ctx *middleware.Context) {
  104. ctx.Data["Title"] = "Migrate repository"
  105. ctx.Data["PageIsNewRepo"] = true
  106. if err := ctx.User.GetOrganizations(); err != nil {
  107. ctx.Handle(500, "home.Migrate(GetOrganizations)", err)
  108. return
  109. }
  110. ctx.Data["Orgs"] = ctx.User.Orgs
  111. ctx.HTML(200, MIGRATE)
  112. }
  113. func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
  114. ctx.Data["Title"] = "Migrate repository"
  115. ctx.Data["PageIsNewRepo"] = true
  116. if err := ctx.User.GetOrganizations(); err != nil {
  117. ctx.Handle(500, "home.MigratePost(GetOrganizations)", err)
  118. return
  119. }
  120. ctx.Data["Orgs"] = ctx.User.Orgs
  121. if ctx.HasError() {
  122. ctx.HTML(200, MIGRATE)
  123. return
  124. }
  125. u := ctx.User
  126. // Not equal means current user is an organization.
  127. if u.Id != form.Uid {
  128. var err error
  129. u, err = models.GetUserById(form.Uid)
  130. if err != nil {
  131. if err == models.ErrUserNotExist {
  132. ctx.Handle(404, "home.MigratePost(GetUserById)", err)
  133. } else {
  134. ctx.Handle(500, "home.MigratePost(GetUserById)", err)
  135. }
  136. return
  137. }
  138. }
  139. authStr := strings.Replace(fmt.Sprintf("://%s:%s",
  140. form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
  141. url := strings.Replace(form.Url, "://", authStr+"@", 1)
  142. repo, err := models.MigrateRepository(u, form.RepoName, form.Description, form.Private,
  143. form.Mirror, url)
  144. if err == nil {
  145. log.Trace("%s Repository migrated: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName)
  146. ctx.Redirect("/" + u.Name + "/" + form.RepoName)
  147. return
  148. } else if err == models.ErrRepoAlreadyExist {
  149. ctx.RenderWithErr("Repository name has already been used", MIGRATE, &form)
  150. return
  151. } else if err == models.ErrRepoNameIllegal {
  152. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), MIGRATE, &form)
  153. return
  154. }
  155. if repo != nil {
  156. if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
  157. log.Error("repo.MigratePost(DeleteRepository): %v", errDelete)
  158. }
  159. }
  160. if strings.Contains(err.Error(), "Authentication failed") {
  161. ctx.RenderWithErr(err.Error(), MIGRATE, &form)
  162. return
  163. }
  164. ctx.Handle(500, "repo.Migrate(MigrateRepository)", err)
  165. }
  166. func Single(ctx *middleware.Context, params martini.Params) {
  167. branchName := ctx.Repo.BranchName
  168. userName := ctx.Repo.Owner.Name
  169. repoName := ctx.Repo.Repository.Name
  170. repoLink := ctx.Repo.RepoLink
  171. branchLink := ctx.Repo.RepoLink + "/src/" + branchName
  172. rawLink := ctx.Repo.RepoLink + "/raw/" + branchName
  173. // Get tree path
  174. treename := params["_1"]
  175. if len(treename) > 0 && treename[len(treename)-1] == '/' {
  176. ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1])
  177. return
  178. }
  179. ctx.Data["IsRepoToolbarSource"] = true
  180. isViewBranch := ctx.Repo.IsBranch
  181. ctx.Data["IsViewBranch"] = isViewBranch
  182. treePath := treename
  183. if len(treePath) != 0 {
  184. treePath = treePath + "/"
  185. }
  186. entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treename)
  187. if err != nil && err != git.ErrNotExist {
  188. ctx.Handle(404, "repo.Single(GetTreeEntryByPath)", err)
  189. return
  190. }
  191. if len(treename) != 0 && entry == nil {
  192. ctx.Handle(404, "repo.Single", nil)
  193. return
  194. }
  195. if entry != nil && !entry.IsDir() {
  196. blob := entry.Blob()
  197. if dataRc, err := blob.Data(); err != nil {
  198. ctx.Handle(404, "repo.Single(blob.Data)", err)
  199. } else {
  200. ctx.Data["FileSize"] = blob.Size()
  201. ctx.Data["IsFile"] = true
  202. ctx.Data["FileName"] = blob.Name()
  203. ext := path.Ext(blob.Name())
  204. if len(ext) > 0 {
  205. ext = ext[1:]
  206. }
  207. ctx.Data["FileExt"] = ext
  208. ctx.Data["FileLink"] = rawLink + "/" + treename
  209. buf := make([]byte, 1024)
  210. n, _ := dataRc.Read(buf)
  211. if n > 0 {
  212. buf = buf[:n]
  213. }
  214. defer func() {
  215. dataRc.Close()
  216. }()
  217. _, isTextFile := base.IsTextFile(buf)
  218. _, isImageFile := base.IsImageFile(buf)
  219. ctx.Data["FileIsText"] = isTextFile
  220. switch {
  221. case isImageFile:
  222. ctx.Data["IsImageFile"] = true
  223. case isTextFile:
  224. d, _ := ioutil.ReadAll(dataRc)
  225. buf = append(buf, d...)
  226. readmeExist := base.IsMarkdownFile(blob.Name()) || base.IsReadmeFile(blob.Name())
  227. ctx.Data["ReadmeExist"] = readmeExist
  228. if readmeExist {
  229. ctx.Data["FileContent"] = string(base.RenderMarkdown(buf, ""))
  230. } else {
  231. ctx.Data["FileContent"] = string(buf)
  232. }
  233. }
  234. }
  235. } else {
  236. // Directory and file list.
  237. tree, err := ctx.Repo.Commit.SubTree(treename)
  238. if err != nil {
  239. ctx.Handle(404, "repo.Single(SubTree)", err)
  240. return
  241. }
  242. entries := tree.ListEntries()
  243. entries.Sort()
  244. files := make([][]interface{}, 0, len(entries))
  245. for _, te := range entries {
  246. c, err := ctx.Repo.Commit.GetCommitOfRelPath(filepath.Join(treePath, te.Name()))
  247. if err != nil {
  248. ctx.Handle(404, "repo.Single(SubTree)", err)
  249. return
  250. }
  251. files = append(files, []interface{}{te, c})
  252. }
  253. ctx.Data["Files"] = files
  254. var readmeFile *git.Blob
  255. for _, f := range entries {
  256. if f.IsDir() || !base.IsReadmeFile(f.Name()) {
  257. continue
  258. } else {
  259. readmeFile = f.Blob()
  260. break
  261. }
  262. }
  263. if readmeFile != nil {
  264. ctx.Data["ReadmeInSingle"] = true
  265. ctx.Data["ReadmeExist"] = true
  266. if dataRc, err := readmeFile.Data(); err != nil {
  267. ctx.Handle(404, "repo.Single(readmeFile.LookupBlob)", err)
  268. return
  269. } else {
  270. buf := make([]byte, 1024)
  271. n, _ := dataRc.Read(buf)
  272. if n > 0 {
  273. buf = buf[:n]
  274. }
  275. defer func() {
  276. dataRc.Close()
  277. }()
  278. ctx.Data["FileSize"] = readmeFile.Size
  279. ctx.Data["FileLink"] = rawLink + "/" + treename
  280. _, isTextFile := base.IsTextFile(buf)
  281. ctx.Data["FileIsText"] = isTextFile
  282. ctx.Data["FileName"] = readmeFile.Name()
  283. if isTextFile {
  284. d, _ := ioutil.ReadAll(dataRc)
  285. buf = append(buf, d...)
  286. switch {
  287. case base.IsMarkdownFile(readmeFile.Name()):
  288. buf = base.RenderMarkdown(buf, branchLink)
  289. default:
  290. buf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1)
  291. }
  292. ctx.Data["FileContent"] = string(buf)
  293. }
  294. }
  295. }
  296. }
  297. ctx.Data["Username"] = userName
  298. ctx.Data["Reponame"] = repoName
  299. var treenames []string
  300. Paths := make([]string, 0)
  301. if len(treename) > 0 {
  302. treenames = strings.Split(treename, "/")
  303. for i, _ := range treenames {
  304. Paths = append(Paths, strings.Join(treenames[0:i+1], "/"))
  305. }
  306. ctx.Data["HasParentPath"] = true
  307. if len(Paths)-2 >= 0 {
  308. ctx.Data["ParentPath"] = "/" + Paths[len(Paths)-2]
  309. }
  310. }
  311. ctx.Data["LastCommit"] = ctx.Repo.Commit
  312. ctx.Data["Paths"] = Paths
  313. ctx.Data["TreeName"] = treename
  314. ctx.Data["Treenames"] = treenames
  315. ctx.Data["TreePath"] = treePath
  316. ctx.Data["BranchLink"] = branchLink
  317. ctx.HTML(200, SINGLE)
  318. }
  319. func basicEncode(username, password string) string {
  320. auth := username + ":" + password
  321. return base64.StdEncoding.EncodeToString([]byte(auth))
  322. }
  323. func basicDecode(encoded string) (user string, name string, err error) {
  324. var s []byte
  325. s, err = base64.StdEncoding.DecodeString(encoded)
  326. if err != nil {
  327. return
  328. }
  329. a := strings.Split(string(s), ":")
  330. if len(a) == 2 {
  331. user, name = a[0], a[1]
  332. } else {
  333. err = errors.New("decode failed")
  334. }
  335. return
  336. }
  337. func authRequired(ctx *middleware.Context) {
  338. ctx.ResponseWriter.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
  339. ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
  340. ctx.HTML(401, base.TplName("status/401"))
  341. }
  342. func Action(ctx *middleware.Context, params martini.Params) {
  343. var err error
  344. switch params["action"] {
  345. case "watch":
  346. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
  347. case "unwatch":
  348. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
  349. case "desc":
  350. if !ctx.Repo.IsOwner {
  351. ctx.Error(404)
  352. return
  353. }
  354. ctx.Repo.Repository.Description = ctx.Query("desc")
  355. ctx.Repo.Repository.Website = ctx.Query("site")
  356. err = models.UpdateRepository(ctx.Repo.Repository)
  357. }
  358. if err != nil {
  359. log.Error("repo.Action(%s): %v", params["action"], err)
  360. ctx.JSON(200, map[string]interface{}{
  361. "ok": false,
  362. "err": err.Error(),
  363. })
  364. return
  365. }
  366. ctx.JSON(200, map[string]interface{}{
  367. "ok": true,
  368. })
  369. }