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 16 kB

11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
6 years ago
11 years ago
11 years ago
10 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
6 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
6 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
6 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
6 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2020 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package repo
  6. import (
  7. "fmt"
  8. "net/url"
  9. "os"
  10. "path"
  11. "strings"
  12. "code.gitea.io/gitea/models"
  13. "code.gitea.io/gitea/modules/auth"
  14. "code.gitea.io/gitea/modules/base"
  15. "code.gitea.io/gitea/modules/context"
  16. "code.gitea.io/gitea/modules/git"
  17. "code.gitea.io/gitea/modules/log"
  18. "code.gitea.io/gitea/modules/migrations"
  19. "code.gitea.io/gitea/modules/setting"
  20. "code.gitea.io/gitea/modules/structs"
  21. "code.gitea.io/gitea/modules/task"
  22. "code.gitea.io/gitea/modules/util"
  23. repo_service "code.gitea.io/gitea/services/repository"
  24. "github.com/unknwon/com"
  25. )
  26. const (
  27. tplCreate base.TplName = "repo/create"
  28. tplMigrate base.TplName = "repo/migrate"
  29. )
  30. // MustBeNotEmpty render when a repo is a empty git dir
  31. func MustBeNotEmpty(ctx *context.Context) {
  32. if ctx.Repo.Repository.IsEmpty {
  33. ctx.NotFound("MustBeNotEmpty", nil)
  34. }
  35. }
  36. // MustBeEditable check that repo can be edited
  37. func MustBeEditable(ctx *context.Context) {
  38. if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
  39. ctx.NotFound("", nil)
  40. return
  41. }
  42. }
  43. // MustBeAbleToUpload check that repo can be uploaded to
  44. func MustBeAbleToUpload(ctx *context.Context) {
  45. if !setting.Repository.Upload.Enabled {
  46. ctx.NotFound("", nil)
  47. }
  48. }
  49. func checkContextUser(ctx *context.Context, uid int64) *models.User {
  50. orgs, err := models.GetOrgsCanCreateRepoByUserID(ctx.User.ID)
  51. if err != nil {
  52. ctx.ServerError("GetOrgsCanCreateRepoByUserID", err)
  53. return nil
  54. }
  55. ctx.Data["Orgs"] = orgs
  56. // Not equal means current user is an organization.
  57. if uid == ctx.User.ID || uid == 0 {
  58. return ctx.User
  59. }
  60. org, err := models.GetUserByID(uid)
  61. if models.IsErrUserNotExist(err) {
  62. return ctx.User
  63. }
  64. if err != nil {
  65. ctx.ServerError("GetUserByID", fmt.Errorf("[%d]: %v", uid, err))
  66. return nil
  67. }
  68. // Check ownership of organization.
  69. if !org.IsOrganization() {
  70. ctx.Error(403)
  71. return nil
  72. }
  73. if !ctx.User.IsAdmin {
  74. canCreate, err := org.CanCreateOrgRepo(ctx.User.ID)
  75. if err != nil {
  76. ctx.ServerError("CanCreateOrgRepo", err)
  77. return nil
  78. } else if !canCreate {
  79. ctx.Error(403)
  80. return nil
  81. }
  82. }
  83. return org
  84. }
  85. func getRepoPrivate(ctx *context.Context) bool {
  86. switch strings.ToLower(setting.Repository.DefaultPrivate) {
  87. case setting.RepoCreatingLastUserVisibility:
  88. return ctx.User.LastRepoVisibility
  89. case setting.RepoCreatingPrivate:
  90. return true
  91. case setting.RepoCreatingPublic:
  92. return false
  93. default:
  94. return ctx.User.LastRepoVisibility
  95. }
  96. }
  97. // Create render creating repository page
  98. func Create(ctx *context.Context) {
  99. if !ctx.User.CanCreateRepo() {
  100. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", ctx.User.MaxCreationLimit()), tplCreate, nil)
  101. }
  102. ctx.Data["Title"] = ctx.Tr("new_repo")
  103. // Give default value for template to render.
  104. ctx.Data["Gitignores"] = models.Gitignores
  105. ctx.Data["LabelTemplates"] = models.LabelTemplates
  106. ctx.Data["Licenses"] = models.Licenses
  107. ctx.Data["Readmes"] = models.Readmes
  108. ctx.Data["readme"] = "Default"
  109. ctx.Data["private"] = getRepoPrivate(ctx)
  110. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  111. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  112. if ctx.Written() {
  113. return
  114. }
  115. ctx.Data["ContextUser"] = ctxUser
  116. ctx.Data["repo_template_name"] = ctx.Tr("repo.template_select")
  117. templateID := ctx.QueryInt64("template_id")
  118. if templateID > 0 {
  119. templateRepo, err := models.GetRepositoryByID(templateID)
  120. if err == nil && templateRepo.CheckUnitUser(ctxUser.ID, ctxUser.IsAdmin, models.UnitTypeCode) {
  121. ctx.Data["repo_template"] = templateID
  122. ctx.Data["repo_template_name"] = templateRepo.Name
  123. }
  124. }
  125. ctx.HTML(200, tplCreate)
  126. }
  127. func handleCreateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) {
  128. switch {
  129. case models.IsErrReachLimitOfRepo(err):
  130. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
  131. case models.IsErrRepoAlreadyExist(err):
  132. ctx.Data["Err_RepoName"] = true
  133. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
  134. case models.IsErrNameReserved(err):
  135. ctx.Data["Err_RepoName"] = true
  136. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
  137. case models.IsErrNamePatternNotAllowed(err):
  138. ctx.Data["Err_RepoName"] = true
  139. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
  140. default:
  141. ctx.ServerError(name, err)
  142. }
  143. }
  144. // CreatePost response for creating repository
  145. func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
  146. ctx.Data["Title"] = ctx.Tr("new_repo")
  147. ctx.Data["Gitignores"] = models.Gitignores
  148. ctx.Data["LabelTemplates"] = models.LabelTemplates
  149. ctx.Data["Licenses"] = models.Licenses
  150. ctx.Data["Readmes"] = models.Readmes
  151. ctxUser := checkContextUser(ctx, form.UID)
  152. if ctx.Written() {
  153. return
  154. }
  155. ctx.Data["ContextUser"] = ctxUser
  156. if ctx.HasError() {
  157. ctx.HTML(200, tplCreate)
  158. return
  159. }
  160. var repo *models.Repository
  161. var err error
  162. if form.RepoTemplate > 0 {
  163. opts := models.GenerateRepoOptions{
  164. Name: form.RepoName,
  165. Description: form.Description,
  166. Private: form.Private,
  167. GitContent: form.GitContent,
  168. Topics: form.Topics,
  169. GitHooks: form.GitHooks,
  170. Webhooks: form.Webhooks,
  171. Avatar: form.Avatar,
  172. IssueLabels: form.Labels,
  173. }
  174. if !opts.IsValid() {
  175. ctx.RenderWithErr(ctx.Tr("repo.template.one_item"), tplCreate, form)
  176. return
  177. }
  178. templateRepo := getRepository(ctx, form.RepoTemplate)
  179. if ctx.Written() {
  180. return
  181. }
  182. if !templateRepo.IsTemplate {
  183. ctx.RenderWithErr(ctx.Tr("repo.template.invalid"), tplCreate, form)
  184. return
  185. }
  186. repo, err = repo_service.GenerateRepository(ctx.User, ctxUser, templateRepo, opts)
  187. if err == nil {
  188. log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
  189. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
  190. return
  191. }
  192. } else {
  193. repo, err = repo_service.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
  194. Name: form.RepoName,
  195. Description: form.Description,
  196. Gitignores: form.Gitignores,
  197. IssueLabels: form.IssueLabels,
  198. License: form.License,
  199. Readme: form.Readme,
  200. IsPrivate: form.Private || setting.Repository.ForcePrivate,
  201. DefaultBranch: form.DefaultBranch,
  202. AutoInit: form.AutoInit,
  203. })
  204. if err == nil {
  205. log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
  206. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
  207. return
  208. }
  209. }
  210. handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
  211. }
  212. // Migrate render migration of repository page
  213. func Migrate(ctx *context.Context) {
  214. ctx.Data["Title"] = ctx.Tr("new_migrate")
  215. ctx.Data["private"] = getRepoPrivate(ctx)
  216. ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
  217. ctx.Data["mirror"] = ctx.Query("mirror") == "1"
  218. ctx.Data["wiki"] = ctx.Query("wiki") == "1"
  219. ctx.Data["milestones"] = ctx.Query("milestones") == "1"
  220. ctx.Data["labels"] = ctx.Query("labels") == "1"
  221. ctx.Data["issues"] = ctx.Query("issues") == "1"
  222. ctx.Data["pull_requests"] = ctx.Query("pull_requests") == "1"
  223. ctx.Data["releases"] = ctx.Query("releases") == "1"
  224. ctx.Data["LFSActive"] = setting.LFS.StartServer
  225. ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
  226. if ctx.Written() {
  227. return
  228. }
  229. ctx.Data["ContextUser"] = ctxUser
  230. ctx.HTML(200, tplMigrate)
  231. }
  232. func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *auth.MigrateRepoForm) {
  233. switch {
  234. case migrations.IsRateLimitError(err):
  235. ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
  236. case migrations.IsTwoFactorAuthError(err):
  237. ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
  238. case models.IsErrReachLimitOfRepo(err):
  239. ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
  240. case models.IsErrRepoAlreadyExist(err):
  241. ctx.Data["Err_RepoName"] = true
  242. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
  243. case models.IsErrNameReserved(err):
  244. ctx.Data["Err_RepoName"] = true
  245. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
  246. case models.IsErrNamePatternNotAllowed(err):
  247. ctx.Data["Err_RepoName"] = true
  248. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
  249. default:
  250. remoteAddr, _ := form.ParseRemoteAddr(owner)
  251. err = util.URLSanitizedError(err, remoteAddr)
  252. if strings.Contains(err.Error(), "Authentication failed") ||
  253. strings.Contains(err.Error(), "Bad credentials") ||
  254. strings.Contains(err.Error(), "could not read Username") {
  255. ctx.Data["Err_Auth"] = true
  256. ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tpl, form)
  257. } else if strings.Contains(err.Error(), "fatal:") {
  258. ctx.Data["Err_CloneAddr"] = true
  259. ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form)
  260. } else {
  261. ctx.ServerError(name, err)
  262. }
  263. }
  264. }
  265. // MigratePost response for migrating from external git repository
  266. func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
  267. ctx.Data["Title"] = ctx.Tr("new_migrate")
  268. ctxUser := checkContextUser(ctx, form.UID)
  269. if ctx.Written() {
  270. return
  271. }
  272. ctx.Data["ContextUser"] = ctxUser
  273. if ctx.HasError() {
  274. ctx.HTML(200, tplMigrate)
  275. return
  276. }
  277. remoteAddr, err := form.ParseRemoteAddr(ctx.User)
  278. if err != nil {
  279. if models.IsErrInvalidCloneAddr(err) {
  280. ctx.Data["Err_CloneAddr"] = true
  281. addrErr := err.(models.ErrInvalidCloneAddr)
  282. switch {
  283. case addrErr.IsURLError:
  284. ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form)
  285. case addrErr.IsPermissionDenied:
  286. ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form)
  287. case addrErr.IsInvalidPath:
  288. ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form)
  289. default:
  290. ctx.ServerError("Unknown error", err)
  291. }
  292. } else {
  293. ctx.ServerError("ParseRemoteAddr", err)
  294. }
  295. return
  296. }
  297. var gitServiceType = structs.PlainGitService
  298. u, err := url.Parse(form.CloneAddr)
  299. if err == nil && strings.EqualFold(u.Host, "github.com") {
  300. gitServiceType = structs.GithubService
  301. }
  302. var opts = migrations.MigrateOptions{
  303. OriginalURL: form.CloneAddr,
  304. GitServiceType: gitServiceType,
  305. CloneAddr: remoteAddr,
  306. RepoName: form.RepoName,
  307. Description: form.Description,
  308. Private: form.Private || setting.Repository.ForcePrivate,
  309. Mirror: form.Mirror,
  310. AuthUsername: form.AuthUsername,
  311. AuthPassword: form.AuthPassword,
  312. Wiki: form.Wiki,
  313. Issues: form.Issues,
  314. Milestones: form.Milestones,
  315. Labels: form.Labels,
  316. Comments: true,
  317. PullRequests: form.PullRequests,
  318. Releases: form.Releases,
  319. }
  320. if opts.Mirror {
  321. opts.Issues = false
  322. opts.Milestones = false
  323. opts.Labels = false
  324. opts.Comments = false
  325. opts.PullRequests = false
  326. opts.Releases = false
  327. }
  328. err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName)
  329. if err != nil {
  330. handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
  331. return
  332. }
  333. err = task.MigrateRepository(ctx.User, ctxUser, opts)
  334. if err == nil {
  335. ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + opts.RepoName)
  336. return
  337. }
  338. handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
  339. }
  340. // Action response for actions to a repository
  341. func Action(ctx *context.Context) {
  342. var err error
  343. switch ctx.Params(":action") {
  344. case "watch":
  345. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  346. case "unwatch":
  347. err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  348. case "star":
  349. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
  350. case "unstar":
  351. err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
  352. case "desc": // FIXME: this is not used
  353. if !ctx.Repo.IsOwner() {
  354. ctx.Error(404)
  355. return
  356. }
  357. ctx.Repo.Repository.Description = ctx.Query("desc")
  358. ctx.Repo.Repository.Website = ctx.Query("site")
  359. err = models.UpdateRepository(ctx.Repo.Repository, false)
  360. }
  361. if err != nil {
  362. ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
  363. return
  364. }
  365. ctx.RedirectToFirst(ctx.Query("redirect_to"), ctx.Repo.RepoLink)
  366. }
  367. // RedirectDownload return a file based on the following infos:
  368. func RedirectDownload(ctx *context.Context) {
  369. var (
  370. vTag = ctx.Params("vTag")
  371. fileName = ctx.Params("fileName")
  372. )
  373. tagNames := []string{vTag}
  374. curRepo := ctx.Repo.Repository
  375. releases, err := models.GetReleasesByRepoIDAndNames(models.DefaultDBContext(), curRepo.ID, tagNames)
  376. if err != nil {
  377. if models.IsErrAttachmentNotExist(err) {
  378. ctx.Error(404)
  379. return
  380. }
  381. ctx.ServerError("RedirectDownload", err)
  382. return
  383. }
  384. if len(releases) == 1 {
  385. release := releases[0]
  386. att, err := models.GetAttachmentByReleaseIDFileName(release.ID, fileName)
  387. if err != nil {
  388. ctx.Error(404)
  389. return
  390. }
  391. if att != nil {
  392. ctx.Redirect(att.DownloadURL())
  393. return
  394. }
  395. }
  396. ctx.Error(404)
  397. }
  398. // Download download an archive of a repository
  399. func Download(ctx *context.Context) {
  400. var (
  401. uri = ctx.Params("*")
  402. refName string
  403. ext string
  404. archivePath string
  405. archiveType git.ArchiveType
  406. )
  407. switch {
  408. case strings.HasSuffix(uri, ".zip"):
  409. ext = ".zip"
  410. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/zip")
  411. archiveType = git.ZIP
  412. case strings.HasSuffix(uri, ".tar.gz"):
  413. ext = ".tar.gz"
  414. archivePath = path.Join(ctx.Repo.GitRepo.Path, "archives/targz")
  415. archiveType = git.TARGZ
  416. default:
  417. log.Trace("Unknown format: %s", uri)
  418. ctx.Error(404)
  419. return
  420. }
  421. refName = strings.TrimSuffix(uri, ext)
  422. if !com.IsDir(archivePath) {
  423. if err := os.MkdirAll(archivePath, os.ModePerm); err != nil {
  424. ctx.ServerError("Download -> os.MkdirAll(archivePath)", err)
  425. return
  426. }
  427. }
  428. // Get corresponding commit.
  429. var (
  430. commit *git.Commit
  431. err error
  432. )
  433. gitRepo := ctx.Repo.GitRepo
  434. if gitRepo.IsBranchExist(refName) {
  435. commit, err = gitRepo.GetBranchCommit(refName)
  436. if err != nil {
  437. ctx.ServerError("GetBranchCommit", err)
  438. return
  439. }
  440. } else if gitRepo.IsTagExist(refName) {
  441. commit, err = gitRepo.GetTagCommit(refName)
  442. if err != nil {
  443. ctx.ServerError("GetTagCommit", err)
  444. return
  445. }
  446. } else if len(refName) >= 4 && len(refName) <= 40 {
  447. commit, err = gitRepo.GetCommit(refName)
  448. if err != nil {
  449. ctx.NotFound("GetCommit", nil)
  450. return
  451. }
  452. } else {
  453. ctx.NotFound("Download", nil)
  454. return
  455. }
  456. archivePath = path.Join(archivePath, base.ShortSha(commit.ID.String())+ext)
  457. if !com.IsFile(archivePath) {
  458. if err := commit.CreateArchive(archivePath, git.CreateArchiveOpts{
  459. Format: archiveType,
  460. Prefix: setting.Repository.PrefixArchiveFiles,
  461. }); err != nil {
  462. ctx.ServerError("Download -> CreateArchive "+archivePath, err)
  463. return
  464. }
  465. }
  466. ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext)
  467. }
  468. // Status returns repository's status
  469. func Status(ctx *context.Context) {
  470. task, err := models.GetMigratingTask(ctx.Repo.Repository.ID)
  471. if err != nil {
  472. ctx.JSON(500, map[string]interface{}{
  473. "err": err,
  474. })
  475. return
  476. }
  477. ctx.JSON(200, map[string]interface{}{
  478. "status": ctx.Repo.Repository.Status,
  479. "err": task.Errors,
  480. })
  481. }