2020-09-09 21:29:10 +03:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/migrations"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/task"
"code.gitea.io/gitea/modules/util"
)
const (
tplMigrate base . TplName = "repo/migrate/migrate"
)
// Migrate render migration of repository page
func Migrate ( ctx * context . Context ) {
ctx . Data [ "Services" ] = append ( [ ] structs . GitServiceType { structs . PlainGitService } , structs . SupportedFullGitService ... )
serviceType := ctx . QueryInt ( "service_type" )
if serviceType == 0 {
ctx . HTML ( 200 , tplMigrate )
return
}
ctx . Data [ "Title" ] = ctx . Tr ( "new_migrate" )
ctx . Data [ "private" ] = getRepoPrivate ( ctx )
ctx . Data [ "IsForcedPrivate" ] = setting . Repository . ForcePrivate
ctx . Data [ "DisableMirrors" ] = setting . Repository . DisableMirrors
ctx . Data [ "mirror" ] = ctx . Query ( "mirror" ) == "1"
ctx . Data [ "wiki" ] = ctx . Query ( "wiki" ) == "1"
ctx . Data [ "milestones" ] = ctx . Query ( "milestones" ) == "1"
ctx . Data [ "labels" ] = ctx . Query ( "labels" ) == "1"
ctx . Data [ "issues" ] = ctx . Query ( "issues" ) == "1"
ctx . Data [ "pull_requests" ] = ctx . Query ( "pull_requests" ) == "1"
ctx . Data [ "releases" ] = ctx . Query ( "releases" ) == "1"
ctx . Data [ "LFSActive" ] = setting . LFS . StartServer
// Plain git should be first
ctx . Data [ "service" ] = structs . GitServiceType ( serviceType )
ctxUser := checkContextUser ( ctx , ctx . QueryInt64 ( "org" ) )
if ctx . Written ( ) {
return
}
ctx . Data [ "ContextUser" ] = ctxUser
ctx . HTML ( 200 , base . TplName ( "repo/migrate/" + structs . GitServiceType ( serviceType ) . Name ( ) ) )
}
func handleMigrateError ( ctx * context . Context , owner * models . User , err error , name string , tpl base . TplName , form * auth . MigrateRepoForm ) {
switch {
case migrations . IsRateLimitError ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "form.visit_rate_limit" ) , tpl , form )
case migrations . IsTwoFactorAuthError ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "form.2fa_auth_required" ) , tpl , form )
case models . IsErrReachLimitOfRepo ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.form.reach_limit_of_creation" , owner . MaxCreationLimit ( ) ) , tpl , form )
case models . IsErrRepoAlreadyExist ( err ) :
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.repo_name_been_taken" ) , tpl , form )
2020-09-25 07:09:23 +03:00
case models . IsErrRepoFilesAlreadyExist ( err ) :
ctx . Data [ "Err_RepoName" ] = true
switch {
case ctx . IsUserSiteAdmin ( ) || ( setting . Repository . AllowAdoptionOfUnadoptedRepositories && setting . Repository . AllowDeleteOfUnadoptedRepositories ) :
ctx . RenderWithErr ( ctx . Tr ( "form.repository_files_already_exist.adopt_or_delete" ) , tpl , form )
case setting . Repository . AllowAdoptionOfUnadoptedRepositories :
ctx . RenderWithErr ( ctx . Tr ( "form.repository_files_already_exist.adopt" ) , tpl , form )
case setting . Repository . AllowDeleteOfUnadoptedRepositories :
ctx . RenderWithErr ( ctx . Tr ( "form.repository_files_already_exist.delete" ) , tpl , form )
default :
ctx . RenderWithErr ( ctx . Tr ( "form.repository_files_already_exist" ) , tpl , form )
}
2020-09-09 21:29:10 +03:00
case models . IsErrNameReserved ( err ) :
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_reserved" , err . ( models . ErrNameReserved ) . Name ) , tpl , form )
case models . IsErrNamePatternNotAllowed ( err ) :
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_pattern_not_allowed" , err . ( models . ErrNamePatternNotAllowed ) . Pattern ) , tpl , form )
default :
2020-09-11 01:29:19 +03:00
remoteAddr , _ := auth . ParseRemoteAddr ( form . CloneAddr , form . AuthUsername , form . AuthPassword , owner )
2020-09-09 21:29:10 +03:00
err = util . URLSanitizedError ( err , remoteAddr )
if strings . Contains ( err . Error ( ) , "Authentication failed" ) ||
strings . Contains ( err . Error ( ) , "Bad credentials" ) ||
strings . Contains ( err . Error ( ) , "could not read Username" ) {
ctx . Data [ "Err_Auth" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.auth_failed" , err . Error ( ) ) , tpl , form )
} else if strings . Contains ( err . Error ( ) , "fatal:" ) {
ctx . Data [ "Err_CloneAddr" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.failed" , err . Error ( ) ) , tpl , form )
} else {
ctx . ServerError ( name , err )
}
}
}
// MigratePost response for migrating from external git repository
func MigratePost ( ctx * context . Context , form auth . MigrateRepoForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "new_migrate" )
// Plain git should be first
2020-09-23 23:25:46 +03:00
ctx . Data [ "service" ] = structs . GitServiceType ( form . Service )
2020-09-09 21:29:10 +03:00
ctx . Data [ "Services" ] = append ( [ ] structs . GitServiceType { structs . PlainGitService } , structs . SupportedFullGitService ... )
2020-09-23 23:25:46 +03:00
tpl := base . TplName ( "repo/migrate/" + structs . GitServiceType ( form . Service ) . Name ( ) )
2020-09-09 21:29:10 +03:00
ctxUser := checkContextUser ( ctx , form . UID )
if ctx . Written ( ) {
return
}
ctx . Data [ "ContextUser" ] = ctxUser
if ctx . HasError ( ) {
2020-09-23 23:25:46 +03:00
ctx . HTML ( 200 , tpl )
2020-09-09 21:29:10 +03:00
return
}
2020-09-11 01:29:19 +03:00
remoteAddr , err := auth . ParseRemoteAddr ( form . CloneAddr , form . AuthUsername , form . AuthPassword , ctx . User )
2020-09-09 21:29:10 +03:00
if err != nil {
if models . IsErrInvalidCloneAddr ( err ) {
ctx . Data [ "Err_CloneAddr" ] = true
addrErr := err . ( models . ErrInvalidCloneAddr )
switch {
case addrErr . IsURLError :
2020-09-23 23:25:46 +03:00
ctx . RenderWithErr ( ctx . Tr ( "form.url_error" ) , tpl , & form )
2020-09-09 21:29:10 +03:00
case addrErr . IsPermissionDenied :
2020-09-23 23:25:46 +03:00
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.permission_denied" ) , tpl , & form )
2020-09-09 21:29:10 +03:00
case addrErr . IsInvalidPath :
2020-09-23 23:25:46 +03:00
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.invalid_local_path" ) , tpl , & form )
2020-09-09 21:29:10 +03:00
default :
ctx . ServerError ( "Unknown error" , err )
}
} else {
ctx . ServerError ( "ParseRemoteAddr" , err )
}
return
}
var opts = migrations . MigrateOptions {
OriginalURL : form . CloneAddr ,
GitServiceType : structs . GitServiceType ( form . Service ) ,
CloneAddr : remoteAddr ,
RepoName : form . RepoName ,
Description : form . Description ,
Private : form . Private || setting . Repository . ForcePrivate ,
Mirror : form . Mirror && ! setting . Repository . DisableMirrors ,
AuthUsername : form . AuthUsername ,
AuthPassword : form . AuthPassword ,
AuthToken : form . AuthToken ,
Wiki : form . Wiki ,
Issues : form . Issues ,
Milestones : form . Milestones ,
Labels : form . Labels ,
Comments : form . Issues || form . PullRequests ,
PullRequests : form . PullRequests ,
Releases : form . Releases ,
}
if opts . Mirror {
opts . Issues = false
opts . Milestones = false
opts . Labels = false
opts . Comments = false
opts . PullRequests = false
opts . Releases = false
}
2020-09-25 07:09:23 +03:00
err = models . CheckCreateRepository ( ctx . User , ctxUser , opts . RepoName , false )
2020-09-09 21:29:10 +03:00
if err != nil {
2020-09-23 23:25:46 +03:00
handleMigrateError ( ctx , ctxUser , err , "MigratePost" , tpl , & form )
2020-09-09 21:29:10 +03:00
return
}
err = task . MigrateRepository ( ctx . User , ctxUser , opts )
if err == nil {
ctx . Redirect ( setting . AppSubURL + "/" + ctxUser . Name + "/" + opts . RepoName )
return
}
2020-09-23 23:25:46 +03:00
handleMigrateError ( ctx , ctxUser , err , "MigratePost" , tpl , & form )
2020-09-09 21:29:10 +03:00
}