|
| 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 | + |
| 6 | +package repo |
| 7 | + |
| 8 | +import ( |
| 9 | + "strings" |
| 10 | + |
| 11 | + "code.gitea.io/gitea/models" |
| 12 | + "code.gitea.io/gitea/modules/auth" |
| 13 | + "code.gitea.io/gitea/modules/base" |
| 14 | + "code.gitea.io/gitea/modules/context" |
| 15 | + "code.gitea.io/gitea/modules/migrations" |
| 16 | + "code.gitea.io/gitea/modules/setting" |
| 17 | + "code.gitea.io/gitea/modules/structs" |
| 18 | + "code.gitea.io/gitea/modules/task" |
| 19 | + "code.gitea.io/gitea/modules/util" |
| 20 | +) |
| 21 | + |
| 22 | +const ( |
| 23 | + tplMigrate base.TplName = "repo/migrate/migrate" |
| 24 | +) |
| 25 | + |
| 26 | +// Migrate render migration of repository page |
| 27 | +func Migrate(ctx *context.Context) { |
| 28 | + ctx.Data["Services"] = append([]structs.GitServiceType{structs.PlainGitService}, structs.SupportedFullGitService...) |
| 29 | + serviceType := ctx.QueryInt("service_type") |
| 30 | + if serviceType == 0 { |
| 31 | + ctx.HTML(200, tplMigrate) |
| 32 | + return |
| 33 | + } |
| 34 | + |
| 35 | + ctx.Data["Title"] = ctx.Tr("new_migrate") |
| 36 | + ctx.Data["private"] = getRepoPrivate(ctx) |
| 37 | + ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate |
| 38 | + ctx.Data["DisableMirrors"] = setting.Repository.DisableMirrors |
| 39 | + ctx.Data["mirror"] = ctx.Query("mirror") == "1" |
| 40 | + ctx.Data["wiki"] = ctx.Query("wiki") == "1" |
| 41 | + ctx.Data["milestones"] = ctx.Query("milestones") == "1" |
| 42 | + ctx.Data["labels"] = ctx.Query("labels") == "1" |
| 43 | + ctx.Data["issues"] = ctx.Query("issues") == "1" |
| 44 | + ctx.Data["pull_requests"] = ctx.Query("pull_requests") == "1" |
| 45 | + ctx.Data["releases"] = ctx.Query("releases") == "1" |
| 46 | + ctx.Data["LFSActive"] = setting.LFS.StartServer |
| 47 | + // Plain git should be first |
| 48 | + ctx.Data["service"] = structs.GitServiceType(serviceType) |
| 49 | + |
| 50 | + ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) |
| 51 | + if ctx.Written() { |
| 52 | + return |
| 53 | + } |
| 54 | + ctx.Data["ContextUser"] = ctxUser |
| 55 | + |
| 56 | + ctx.HTML(200, base.TplName("repo/migrate/"+structs.GitServiceType(serviceType).Name())) |
| 57 | +} |
| 58 | + |
| 59 | +func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *auth.MigrateRepoForm) { |
| 60 | + switch { |
| 61 | + case migrations.IsRateLimitError(err): |
| 62 | + ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form) |
| 63 | + case migrations.IsTwoFactorAuthError(err): |
| 64 | + ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form) |
| 65 | + case models.IsErrReachLimitOfRepo(err): |
| 66 | + ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form) |
| 67 | + case models.IsErrRepoAlreadyExist(err): |
| 68 | + ctx.Data["Err_RepoName"] = true |
| 69 | + ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form) |
| 70 | + case models.IsErrNameReserved(err): |
| 71 | + ctx.Data["Err_RepoName"] = true |
| 72 | + ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form) |
| 73 | + case models.IsErrNamePatternNotAllowed(err): |
| 74 | + ctx.Data["Err_RepoName"] = true |
| 75 | + ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) |
| 76 | + default: |
| 77 | + remoteAddr, _ := form.ParseRemoteAddr(owner) |
| 78 | + err = util.URLSanitizedError(err, remoteAddr) |
| 79 | + if strings.Contains(err.Error(), "Authentication failed") || |
| 80 | + strings.Contains(err.Error(), "Bad credentials") || |
| 81 | + strings.Contains(err.Error(), "could not read Username") { |
| 82 | + ctx.Data["Err_Auth"] = true |
| 83 | + ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tpl, form) |
| 84 | + } else if strings.Contains(err.Error(), "fatal:") { |
| 85 | + ctx.Data["Err_CloneAddr"] = true |
| 86 | + ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form) |
| 87 | + } else { |
| 88 | + ctx.ServerError(name, err) |
| 89 | + } |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +// MigratePost response for migrating from external git repository |
| 94 | +func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { |
| 95 | + ctx.Data["Title"] = ctx.Tr("new_migrate") |
| 96 | + // Plain git should be first |
| 97 | + ctx.Data["service"] = form.Service |
| 98 | + ctx.Data["Services"] = append([]structs.GitServiceType{structs.PlainGitService}, structs.SupportedFullGitService...) |
| 99 | + |
| 100 | + ctxUser := checkContextUser(ctx, form.UID) |
| 101 | + if ctx.Written() { |
| 102 | + return |
| 103 | + } |
| 104 | + ctx.Data["ContextUser"] = ctxUser |
| 105 | + |
| 106 | + if ctx.HasError() { |
| 107 | + ctx.HTML(200, tplMigrate) |
| 108 | + return |
| 109 | + } |
| 110 | + |
| 111 | + remoteAddr, err := form.ParseRemoteAddr(ctx.User) |
| 112 | + if err != nil { |
| 113 | + if models.IsErrInvalidCloneAddr(err) { |
| 114 | + ctx.Data["Err_CloneAddr"] = true |
| 115 | + addrErr := err.(models.ErrInvalidCloneAddr) |
| 116 | + switch { |
| 117 | + case addrErr.IsURLError: |
| 118 | + ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form) |
| 119 | + case addrErr.IsPermissionDenied: |
| 120 | + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form) |
| 121 | + case addrErr.IsInvalidPath: |
| 122 | + ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form) |
| 123 | + default: |
| 124 | + ctx.ServerError("Unknown error", err) |
| 125 | + } |
| 126 | + } else { |
| 127 | + ctx.ServerError("ParseRemoteAddr", err) |
| 128 | + } |
| 129 | + return |
| 130 | + } |
| 131 | + |
| 132 | + var opts = migrations.MigrateOptions{ |
| 133 | + OriginalURL: form.CloneAddr, |
| 134 | + GitServiceType: structs.GitServiceType(form.Service), |
| 135 | + CloneAddr: remoteAddr, |
| 136 | + RepoName: form.RepoName, |
| 137 | + Description: form.Description, |
| 138 | + Private: form.Private || setting.Repository.ForcePrivate, |
| 139 | + Mirror: form.Mirror && !setting.Repository.DisableMirrors, |
| 140 | + AuthUsername: form.AuthUsername, |
| 141 | + AuthPassword: form.AuthPassword, |
| 142 | + AuthToken: form.AuthToken, |
| 143 | + Wiki: form.Wiki, |
| 144 | + Issues: form.Issues, |
| 145 | + Milestones: form.Milestones, |
| 146 | + Labels: form.Labels, |
| 147 | + Comments: form.Issues || form.PullRequests, |
| 148 | + PullRequests: form.PullRequests, |
| 149 | + Releases: form.Releases, |
| 150 | + } |
| 151 | + if opts.Mirror { |
| 152 | + opts.Issues = false |
| 153 | + opts.Milestones = false |
| 154 | + opts.Labels = false |
| 155 | + opts.Comments = false |
| 156 | + opts.PullRequests = false |
| 157 | + opts.Releases = false |
| 158 | + } |
| 159 | + |
| 160 | + err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName) |
| 161 | + if err != nil { |
| 162 | + handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) |
| 163 | + return |
| 164 | + } |
| 165 | + |
| 166 | + err = task.MigrateRepository(ctx.User, ctxUser, opts) |
| 167 | + if err == nil { |
| 168 | + ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + opts.RepoName) |
| 169 | + return |
| 170 | + } |
| 171 | + |
| 172 | + handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) |
| 173 | +} |
0 commit comments