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.

332 lines
8.7 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 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. "net/url"
  8. "os"
  9. "path"
  10. "strings"
  11. "github.com/Unknwon/com"
  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/git"
  16. "github.com/gogits/gogs/modules/log"
  17. "github.com/gogits/gogs/modules/middleware"
  18. "github.com/gogits/gogs/modules/setting"
  19. )
  20. const (
  21. CREATE base.TplName = "repo/create"
  22. MIGRATE base.TplName = "repo/migrate"
  23. )
  24. func checkContextUser(ctx *middleware.Context, uid int64) *models.User {
  25. orgs, err := models.GetOwnedOrgsByUserIDDesc(ctx.User.Id, "updated")
  26. if err != nil {
  27. ctx.Handle(500, "GetOwnedOrgsByUserIDDesc", err)
  28. return nil
  29. }
  30. ctx.Data["Orgs"] = orgs
  31. // Not equal means current user is an organization.
  32. if uid == ctx.User.Id || uid == 0 {
  33. return ctx.User
  34. }
  35. org, err := models.GetUserByID(uid)
  36. if models.IsErrUserNotExist(err) {
  37. return ctx.User
  38. }
  39. if err != nil {
  40. ctx.Handle(500, "GetUserByID", fmt.Errorf("[%d]: %v", uid, err))
  41. return nil
  42. }
  43. // Check ownership of organization.
  44. if !org.IsOrganization() || !org.IsOwnedBy(ctx.User.Id) {
  45. ctx.Error(403)
  46. return nil
  47. }
  48. return org
  49. }
  50. func Create(ctx *middleware.Context) {
  51. ctx.Data["Title"] = ctx.Tr("new_repo")
  52. // Give default value for template to render.
  53. ctx.Data["Gitignores"] = models.Gitignores
  54. ctx.Data["Licenses"] = models.Licenses
  55. ctx.Data["Readmes"] = models.Readmes
  56. ctx.Data["readme"] = "Default"
  57. ctx.Data["private"] = ctx.User.LastRepoVisibility
  58. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  59. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  60. if ctx.Written() {
  61. return
  62. }
  63. ctx.Data["ContextUser"] = ctxUser
  64. ctx.HTML(200, CREATE)
  65. }
  66. func handleCreateError(ctx *middleware.Context, err error, name string, tpl base.TplName, form interface{}) {
  67. switch {
  68. case models.IsErrRepoAlreadyExist(err):
  69. ctx.Data["Err_RepoName"] = true
  70. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
  71. case models.IsErrNameReserved(err):
  72. ctx.Data["Err_RepoName"] = true
  73. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
  74. case models.IsErrNamePatternNotAllowed(err):
  75. ctx.Data["Err_RepoName"] = true
  76. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
  77. default:
  78. ctx.Handle(500, name, err)
  79. }
  80. }
  81. func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
  82. ctx.Data["Title"] = ctx.Tr("new_repo")
  83. ctx.Data["Gitignores"] = models.Gitignores
  84. ctx.Data["Licenses"] = models.Licenses
  85. ctx.Data["Readmes"] = models.Readmes
  86. ctxUser := checkContextUser(ctx, form.Uid)
  87. if ctx.Written() {
  88. return
  89. }
  90. ctx.Data["ContextUser"] = ctxUser
  91. if ctx.HasError() {
  92. ctx.HTML(200, CREATE)
  93. return
  94. }
  95. repo, err := models.CreateRepository(ctxUser, models.CreateRepoOptions{
  96. Name: form.RepoName,
  97. Description: form.Description,
  98. Gitignores: form.Gitignores,
  99. License: form.License,
  100. Readme: form.Readme,
  101. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  102. AutoInit: form.AutoInit,
  103. })
  104. if err == nil {
  105. log.Trace("Repository created[%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
  106. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
  107. return
  108. }
  109. if repo != nil {
  110. if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil {
  111. log.Error(4, "DeleteRepository: %v", errDelete)
  112. }
  113. }
  114. handleCreateError(ctx, err, "CreatePost", CREATE, &form)
  115. }
  116. func Migrate(ctx *middleware.Context) {
  117. ctx.Data["Title"] = ctx.Tr("new_migrate")
  118. ctx.Data["private"] = ctx.User.LastRepoVisibility
  119. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  120. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  121. if ctx.Written() {
  122. return
  123. }
  124. ctx.Data["ContextUser"] = ctxUser
  125. ctx.HTML(200, MIGRATE)
  126. }
  127. func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
  128. ctx.Data["Title"] = ctx.Tr("new_migrate")
  129. ctxUser := checkContextUser(ctx, form.Uid)
  130. if ctx.Written() {
  131. return
  132. }
  133. ctx.Data["ContextUser"] = ctxUser
  134. if ctx.HasError() {
  135. ctx.HTML(200, MIGRATE)
  136. return
  137. }
  138. // Remote address can be HTTP/HTTPS/Git URL or local path.
  139. // Note: remember to change api/v1/repo.go: MigrateRepo
  140. // FIXME: merge these two functions with better error handling
  141. remoteAddr := form.CloneAddr
  142. if strings.HasPrefix(form.CloneAddr, "http://") ||
  143. strings.HasPrefix(form.CloneAddr, "https://") ||
  144. strings.HasPrefix(form.CloneAddr, "git://") {
  145. u, err := url.Parse(form.CloneAddr)
  146. if err != nil {
  147. ctx.Data["Err_CloneAddr"] = true
  148. ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form)
  149. return
  150. }
  151. if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 {
  152. u.User = url.UserPassword(form.AuthUsername, form.AuthPassword)
  153. }
  154. remoteAddr = u.String()
  155. } else if !com.IsDir(remoteAddr) {
  156. ctx.Data["Err_CloneAddr"] = true
  157. ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form)
  158. return
  159. }
  160. repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
  161. Name: form.RepoName,
  162. Description: form.Description,
  163. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  164. IsMirror: form.Mirror,
  165. RemoteAddr: remoteAddr,
  166. })
  167. if err == nil {
  168. log.Trace("Repository migrated[%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName)
  169. ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName)
  170. return
  171. }
  172. if repo != nil {
  173. if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil {
  174. log.Error(4, "DeleteRepository: %v", errDelete)
  175. }
  176. }
  177. if strings.Contains(err.Error(), "Authentication failed") ||
  178. strings.Contains(err.Error(), " not found") ||
  179. strings.Contains(err.Error(), "could not read Username") {
  180. ctx.Data["Err_Auth"] = true
  181. ctx.RenderWithErr(ctx.Tr("form.auth_failed", strings.Replace(err.Error(), ":"+form.AuthPassword+"@", ":<password>@", 1)), MIGRATE, &form)
  182. return
  183. }
  184. handleCreateError(ctx, err, "MigratePost", MIGRATE, &form)
  185. }
  186. func Action(ctx *middleware.Context) {
  187. var err error
  188. switch ctx.Params(":action") {
  189. case "watch":
  190. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.ID, true)
  191. case "unwatch":
  192. err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.ID, false)
  193. case "star":
  194. err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.ID, true)
  195. case "unstar":
  196. err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.ID, false)
  197. case "desc":
  198. if !ctx.Repo.IsOwner() {
  199. ctx.Error(404)
  200. return
  201. }
  202. ctx.Repo.Repository.Description = ctx.Query("desc")
  203. ctx.Repo.Repository.Website = ctx.Query("site")
  204. err = models.UpdateRepository(ctx.Repo.Repository, false)
  205. }
  206. if err != nil {
  207. log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
  208. ctx.JSON(200, map[string]interface{}{
  209. "ok": false,
  210. "err": err.Error(),
  211. })
  212. return
  213. }
  214. redirectTo := ctx.Query("redirect_to")
  215. if len(redirectTo) == 0 {
  216. redirectTo = ctx.Repo.RepoLink
  217. }
  218. ctx.Redirect(redirectTo)
  219. return
  220. ctx.JSON(200, map[string]interface{}{
  221. "ok": true,
  222. })
  223. }
  224. func Download(ctx *middleware.Context) {
  225. var (
  226. uri = ctx.Params("*")
  227. refName string
  228. ext string
  229. archivePath string
  230. archiveType git.ArchiveType
  231. )
  232. switch {
  233. case strings.HasSuffix(uri, ".zip"):
  234. ext = ".zip"
  235. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  236. archiveType = git.ZIP
  237. case strings.HasSuffix(uri, ".tar.gz"):
  238. ext = ".tar.gz"
  239. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  240. archiveType = git.TARGZ
  241. default:
  242. ctx.Error(404)
  243. return
  244. }
  245. refName = strings.TrimSuffix(uri, ext)
  246. if !com.IsDir(archivePath) {
  247. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  248. ctx.Handle(500, "Download -> os.MkdirAll(archivePath)", err)
  249. return
  250. }
  251. }
  252. // Get corresponding commit.
  253. var (
  254. commit *git.Commit
  255. err error
  256. )
  257. gitRepo := ctx.Repo.GitRepo
  258. if gitRepo.IsBranchExist(refName) {
  259. commit, err = gitRepo.GetCommitOfBranch(refName)
  260. if err != nil {
  261. ctx.Handle(500, "Download", err)
  262. return
  263. }
  264. } else if gitRepo.IsTagExist(refName) {
  265. commit, err = gitRepo.GetCommitOfTag(refName)
  266. if err != nil {
  267. ctx.Handle(500, "Download", err)
  268. return
  269. }
  270. } else if len(refName) == 40 {
  271. commit, err = gitRepo.GetCommit(refName)
  272. if err != nil {
  273. ctx.Handle(404, "Download", nil)
  274. return
  275. }
  276. } else {
  277. ctx.Error(404)
  278. return
  279. }
  280. archivePath = path.Join(archivePath, base.ShortSha(commit.Id.String())+ext)
  281. if !com.IsFile(archivePath) {
  282. if err := commit.CreateArchive(archivePath, archiveType); err != nil {
  283. ctx.Handle(500, "Download -> CreateArchive "+archivePath, err)
  284. return
  285. }
  286. }
  287. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+base.ShortSha(commit.Id.String())+ext)
  288. }