diff --git a/cmd/web.go b/cmd/web.go index 4b06a882c0..1b692ceb48 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -79,7 +79,7 @@ func checkVersion() { // Check dependency version. checkers := []VerChecker{ {"github.com/Unknwon/macaron", macaron.Version, "0.5.1"}, - {"github.com/macaron-contrib/binding", binding.Version, "0.0.4"}, + {"github.com/macaron-contrib/binding", binding.Version, "0.0.5"}, {"github.com/macaron-contrib/cache", cache.Version, "0.0.7"}, {"github.com/macaron-contrib/csrf", csrf.Version, "0.0.3"}, {"github.com/macaron-contrib/i18n", i18n.Version, "0.0.5"}, @@ -229,7 +229,7 @@ func runWeb(ctx *cli.Context) { }) m.Any("/*", func(ctx *middleware.Context) { - ctx.JSON(404, &base.ApiJsonErr{"Not Found", base.DOC_URL}) + ctx.HandleAPI(404, "Page not found") }) }) }) diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini index 54b80abb5e..ca076b8bb4 100644 --- a/conf/locale/locale_en-US.ini +++ b/conf/locale/locale_en-US.ini @@ -286,6 +286,8 @@ need_auth = Need Authorization migrate_type = Migration Type migrate_type_helper = This repository will be a Mirror migrate_repo = Migrate Repository +migrate.clone_address = Clone Address +migrate.invalid_local_path = Invalid local path, it does not exist or not a directory. copy_link = Copy click_to_copy = Copy to clipboard diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index c771dd59b8..2902a92f2e 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -31,7 +31,7 @@ func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bin } type MigrateRepoForm struct { - HttpsUrl string `form:"url" binding:"Required;Url"` + CloneAddr string `binding:"Required"` AuthUserName string `form:"auth_username"` AuthPasswd string `form:"auth_password"` Uid int64 `form:"uid" binding:"Required"` diff --git a/modules/middleware/context.go b/modules/middleware/context.go index 28be3a3025..45779d5800 100644 --- a/modules/middleware/context.go +++ b/modules/middleware/context.go @@ -130,6 +130,18 @@ func (ctx *Context) Handle(status int, title string, err error) { ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status))) } +func (ctx *Context) HandleAPI(status int, obj interface{}) { + var message string + if err, ok := obj.(error); ok { + message = err.Error() + } else { + message = obj.(string) + } + ctx.JSON(status, map[string]string{ + "message": message, + }) +} + func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) { modtime := time.Now() for _, p := range params { diff --git a/routers/api/v1/repo.go b/routers/api/v1/repo.go index fbf9c73ea7..fde184d994 100644 --- a/routers/api/v1/repo.go +++ b/routers/api/v1/repo.go @@ -5,7 +5,7 @@ package v1 import ( - "fmt" + "net/url" "path" "strings" @@ -156,17 +156,15 @@ func CreateOrgRepo(ctx *middleware.Context, opt api.CreateRepoOption) { func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { u, err := models.GetUserByName(ctx.Query("username")) if err != nil { - ctx.JSON(500, map[string]interface{}{ - "ok": false, - "error": err.Error(), - }) + if err == models.ErrUserNotExist { + ctx.HandleAPI(422, err) + } else { + ctx.HandleAPI(500, err) + } return } if !u.ValidtePassword(ctx.Query("password")) { - ctx.JSON(500, map[string]interface{}{ - "ok": false, - "error": "username or password is not correct", - }) + ctx.HandleAPI(422, "Username or password is not correct.") return } @@ -175,56 +173,59 @@ func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { if form.Uid != u.Id { org, err := models.GetUserById(form.Uid) if err != nil { - log.Error(4, "GetUserById: %v", err) - ctx.Error(500) + if err == models.ErrUserNotExist { + ctx.HandleAPI(422, err) + } else { + ctx.HandleAPI(500, err) + } return } ctxUser = org } if ctx.HasError() { - ctx.JSON(422, map[string]interface{}{ - "ok": false, - "error": ctx.GetErrMsg(), - }) + ctx.HandleAPI(422, ctx.GetErrMsg()) return } if ctxUser.IsOrganization() { // Check ownership of organization. if !ctxUser.IsOwnedBy(u.Id) { - ctx.JSON(403, map[string]interface{}{ - "ok": false, - "error": "given user is not owner of organization", - }) + ctx.HandleAPI(403, "Given user is not owner of organization.") return } } - authStr := strings.Replace(fmt.Sprintf("://%s:%s", - form.AuthUserName, form.AuthPasswd), "@", "%40", -1) - url := strings.Replace(form.HttpsUrl, "://", authStr+"@", 1) - repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, - form.Mirror, url) - if err == nil { - log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) - ctx.JSON(200, map[string]interface{}{ - "ok": true, - "data": "/" + ctxUser.Name + "/" + form.RepoName, - }) + // Remote address can be HTTPS URL or local path. + remoteAddr := form.CloneAddr + if strings.HasPrefix(form.CloneAddr, "http") { + u, err := url.Parse(form.CloneAddr) + if err != nil { + ctx.HandleAPI(422, err) + return + } + if len(form.AuthUserName) > 0 || len(form.AuthPasswd) > 0 { + u.User = url.UserPassword(form.AuthUserName, form.AuthPasswd) + } + remoteAddr = u.String() + } else if !com.IsDir(remoteAddr) { + ctx.HandleAPI(422, "Invalid local path, it does not exist or not a directory.") return } - if repo != nil { - if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil { - log.Error(4, "DeleteRepository: %v", errDelete) + repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) + if err != nil { + if repo != nil { + if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil { + log.Error(4, "DeleteRepository: %v", errDelete) + } } + ctx.HandleAPI(500, err) + return } - ctx.JSON(500, map[string]interface{}{ - "ok": false, - "error": err.Error(), - }) + log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) + ctx.WriteHeader(200) } // GET /user/repos diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 48f7b09bc0..dfd827bbb9 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -181,20 +181,26 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { } } - u, err := url.Parse(form.HttpsUrl) - - if err != nil || u.Scheme != "https" { - ctx.Data["Err_HttpsUrl"] = true - ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form) + // Remote address can be HTTPS URL or local path. + remoteAddr := form.CloneAddr + if strings.HasPrefix(form.CloneAddr, "http") { + u, err := url.Parse(form.CloneAddr) + if err != nil { + ctx.Data["Err_CloneAddr"] = true + ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form) + return + } + if len(form.AuthUserName) > 0 || len(form.AuthPasswd) > 0 { + u.User = url.UserPassword(form.AuthUserName, form.AuthPasswd) + } + remoteAddr = u.String() + } else if !com.IsDir(remoteAddr) { + ctx.Data["Err_CloneAddr"] = true + ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form) return } - if len(form.AuthUserName) > 0 || len(form.AuthPasswd) > 0 { - u.User = url.UserPassword(form.AuthUserName, form.AuthPasswd) - } - - repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, - form.Mirror, u.String()) + repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) if err == nil { log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) diff --git a/templates/repo/migrate.tmpl b/templates/repo/migrate.tmpl index b28d06475c..5869be1558 100644 --- a/templates/repo/migrate.tmpl +++ b/templates/repo/migrate.tmpl @@ -7,8 +7,8 @@