From edf14202fea349500d69ed2a360a53cc0d1f80e3 Mon Sep 17 00:00:00 2001
From: Gusted <williamzijl7@hotmail.com>
Date: Sun, 12 Jun 2022 07:43:27 +0200
Subject: [PATCH] Unify repo settings & show better error (#19828)

* Unify context data
* Actually show invalid url in error
---
 modules/web/middleware/binding.go |  2 +-
 options/locale/locale_en-US.ini   |  2 +-
 routers/web/repo/migrate.go       |  6 +++---
 routers/web/repo/setting.go       | 12 +++++++-----
 routers/web/web.go                |  6 ++++--
 services/forms/repo_form.go       |  2 +-
 services/migrations/migrate.go    |  2 +-
 7 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/modules/web/middleware/binding.go b/modules/web/middleware/binding.go
index c9dc4a8f59..88a3920f6e 100644
--- a/modules/web/middleware/binding.go
+++ b/modules/web/middleware/binding.go
@@ -128,7 +128,7 @@ func Validate(errs binding.Errors, data map[string]interface{}, f Form, l transl
 			case binding.ERR_EMAIL:
 				data["ErrorMsg"] = trName + l.Tr("form.email_error")
 			case binding.ERR_URL:
-				data["ErrorMsg"] = trName + l.Tr("form.url_error")
+				data["ErrorMsg"] = trName + l.Tr("form.url_error", errs[0].Message)
 			case binding.ERR_INCLUDE:
 				data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
 			case validation.ErrGlobPattern:
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index b1c3247315..f1c164660d 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -443,7 +443,7 @@ size_error = ` must be size %s.`
 min_size_error = ` must contain at least %s characters.`
 max_size_error = ` must contain at most %s characters.`
 email_error = ` is not a valid email address.`
-url_error = ` is not a valid URL.`
+url_error = `'%s' is not a valid URL.`
 include_error = ` must contain substring '%s'.`
 glob_pattern_error = ` glob pattern is invalid: %s.`
 regex_pattern_error = ` regex pattern is invalid: %s.`
diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go
index 38cdbd4973..393f8ed3d9 100644
--- a/routers/web/repo/migrate.go
+++ b/routers/web/repo/migrate.go
@@ -128,7 +128,7 @@ func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl base.TplN
 		case addrErr.IsProtocolInvalid:
 			ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tpl, form)
 		case addrErr.IsURLError:
-			ctx.RenderWithErr(ctx.Tr("form.url_error"), tpl, form)
+			ctx.RenderWithErr(ctx.Tr("form.url_error", addrErr.Host), tpl, form)
 		case addrErr.IsPermissionDenied:
 			if addrErr.LocalPath {
 				ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tpl, form)
@@ -139,11 +139,11 @@ func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl base.TplN
 			ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tpl, form)
 		default:
 			log.Error("Error whilst updating url: %v", err)
-			ctx.RenderWithErr(ctx.Tr("form.url_error"), tpl, form)
+			ctx.RenderWithErr(ctx.Tr("form.url_error", "unknown"), tpl, form)
 		}
 	} else {
 		log.Error("Error whilst updating url: %v", err)
-		ctx.RenderWithErr(ctx.Tr("form.url_error"), tpl, form)
+		ctx.RenderWithErr(ctx.Tr("form.url_error", "unknown"), tpl, form)
 	}
 }
 
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index 6083d17fa5..fae62c1020 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -57,8 +57,9 @@ const (
 	tplProtectedBranch base.TplName = "repo/settings/protected_branch"
 )
 
-// Settings show a repository's settings page
-func Settings(ctx *context.Context) {
+// SettingsCtxData is a middleware that sets all the general context data for the
+// settings template.
+func SettingsCtxData(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("repo.settings")
 	ctx.Data["PageIsSettingsOptions"] = true
 	ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
@@ -94,15 +95,16 @@ func Settings(ctx *context.Context) {
 		return
 	}
 	ctx.Data["PushMirrors"] = pushMirrors
+}
 
+// Settings show a repository's settings page
+func Settings(ctx *context.Context) {
 	ctx.HTML(http.StatusOK, tplSettingsOptions)
 }
 
 // SettingsPost response for changes of a repository
 func SettingsPost(ctx *context.Context) {
 	form := web.GetForm(ctx).(*forms.RepoSettingForm)
-	ctx.Data["Title"] = ctx.Tr("repo.settings")
-	ctx.Data["PageIsSettingsOptions"] = true
 
 	ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
 	ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled
@@ -827,7 +829,7 @@ func handleSettingRemoteAddrError(ctx *context.Context, err error, form *forms.R
 		case addrErr.IsProtocolInvalid:
 			ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, form)
 		case addrErr.IsURLError:
-			ctx.RenderWithErr(ctx.Tr("form.url_error"), tplSettingsOptions, form)
+			ctx.RenderWithErr(ctx.Tr("form.url_error", addrErr.Host), tplSettingsOptions, form)
 		case addrErr.IsPermissionDenied:
 			if addrErr.LocalPath {
 				ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplSettingsOptions, form)
diff --git a/routers/web/web.go b/routers/web/web.go
index dc596c6970..ad005f74df 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -730,8 +730,10 @@ func RegisterRoutes(m *web.Route) {
 
 	m.Group("/{username}/{reponame}", func() {
 		m.Group("/settings", func() {
-			m.Combo("").Get(repo.Settings).
-				Post(bindIgnErr(forms.RepoSettingForm{}), repo.SettingsPost)
+			m.Group("", func() {
+				m.Combo("").Get(repo.Settings).
+					Post(bindIgnErr(forms.RepoSettingForm{}), repo.SettingsPost)
+			}, repo.SettingsCtxData)
 			m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), repo.SettingsAvatar)
 			m.Post("/avatar/delete", repo.SettingsDeleteAvatar)
 
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index 738a77d2bb..23ac1abe3c 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -101,7 +101,7 @@ func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, err
 		strings.HasPrefix(remoteAddr, "git://") {
 		u, err := url.Parse(remoteAddr)
 		if err != nil {
-			return "", &models.ErrInvalidCloneAddr{IsURLError: true}
+			return "", &models.ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr}
 		}
 		if len(authUsername)+len(authPassword) > 0 {
 			u.User = url.UserPassword(authUsername, authPassword)
diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go
index 700f06af35..ce76733bd5 100644
--- a/services/migrations/migrate.go
+++ b/services/migrations/migrate.go
@@ -44,7 +44,7 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error {
 	// Remote address can be HTTP/HTTPS/Git URL or local path.
 	u, err := url.Parse(remoteURL)
 	if err != nil {
-		return &models.ErrInvalidCloneAddr{IsURLError: true}
+		return &models.ErrInvalidCloneAddr{IsURLError: true, Host: remoteURL}
 	}
 
 	if u.Scheme == "file" || u.Scheme == "" {