From a6f961fba416e146f5da6cb18115d2f6251d4fe3 Mon Sep 17 00:00:00 2001
From: wxiaoguang <wxiaoguang@gmail.com>
Date: Tue, 7 Dec 2021 13:44:08 +0800
Subject: [PATCH] Refactor install page (db type) (#17919)

* Refactor install page (db type)

* set correct default DB HOST for different DB TYPE
* remove legacy TiDB from documents
* unify the usage of DB TYPE, in code we only use "mysql". "MySQL" is only shown to users for friendly name.

* Gitea can use TiDB via MySQL protocol

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
---
 .../doc/advanced/config-cheat-sheet.zh-cn.md  |  4 +-
 docs/content/page/index.en-us.md              |  2 +-
 docs/content/page/index.fr-fr.md              |  2 +-
 docs/content/page/index.zh-cn.md              |  2 +-
 docs/content/page/index.zh-tw.md              |  2 +-
 models/engine_test.go                         |  3 +-
 modules/setting/database.go                   | 12 ++--
 modules/setting/database_sqlite.go            |  2 +-
 options/locale/locale_en-US.ini               |  2 +-
 routers/install/install.go                    | 37 ++++++-----
 templates/admin/config.tmpl                   |  4 +-
 templates/install.tmpl                        | 18 +++---
 web_src/js/features/install.js                | 63 ++++++++-----------
 web_src/less/_install.less                    |  2 +-
 14 files changed, 75 insertions(+), 80 deletions(-)

diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
index 7e02596f7b..02e0e6c914 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
@@ -84,14 +84,14 @@ menu:
 
 ## Database (`database`)
 
-- `DB_TYPE`: 数据库类型,可选 `mysql`, `postgres`, `mssql`, `tidb` 或 `sqlite3`。
+- `DB_TYPE`: 数据库类型,可选 `mysql`, `postgres`, `mssql` 或 `sqlite3`。
 - `HOST`: 数据库服务器地址和端口。
 - `NAME`: 数据库名称。
 - `USER`: 数据库用户名。
 - `PASSWD`: 数据库用户密码。
 - `SSL_MODE`: MySQL 或 PostgreSQL数据库是否启用SSL模式。
 - `CHARSET`: **utf8mb4**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。
-- `PATH`: Tidb 或者 SQLite3 数据文件存放路径。
+- `PATH`: SQLite3 数据文件存放路径。
 - `LOG_SQL`: **true**: 显示生成的SQL,默认为真。
 - `MAX_IDLE_CONNS` **0**: 最大空闲数据库连接
 - `CONN_MAX_LIFETIME` **3s**: 数据库连接最大存活时间
diff --git a/docs/content/page/index.en-us.md b/docs/content/page/index.en-us.md
index 48ca13cc66..087278a83f 100644
--- a/docs/content/page/index.en-us.md
+++ b/docs/content/page/index.en-us.md
@@ -73,7 +73,7 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others.
         - PostgreSQL (>=10)
         - SQLite3
         - MSSQL (>=2008R2 SP3)
-        - TiDB (experimental, not recommended)
+        - TiDB (MySQL protocol)
     - Configuration file
         - [app.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini)
     - Admin panel
diff --git a/docs/content/page/index.fr-fr.md b/docs/content/page/index.fr-fr.md
index 17e22e8b59..711e163deb 100755
--- a/docs/content/page/index.fr-fr.md
+++ b/docs/content/page/index.fr-fr.md
@@ -68,7 +68,7 @@ Le but de ce projet est de fournir de la manière la plus simple, la plus rapide
         - PostgreSQL
         - SQLite3
         - MSSQL
-        - [TiDB](https://github.com/pingcap/tidb) (expérimental)
+        - [TiDB](https://github.com/pingcap/tidb) (MySQL protocol)
     - Fichier de configuration
         - Voir [ici](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini)
     - Panel d'administration
diff --git a/docs/content/page/index.zh-cn.md b/docs/content/page/index.zh-cn.md
index cb6a1da793..9aa1e6a8bc 100644
--- a/docs/content/page/index.zh-cn.md
+++ b/docs/content/page/index.zh-cn.md
@@ -32,7 +32,7 @@ Gitea的首要目标是创建一个极易安装,运行非常快速,安装和
 - 支持自定义源的 Gravatar 和 Federated Avatar
 - 支持邮件服务
 - 支持后台管理面板
-- 支持 MySQL、PostgreSQL、SQLite3, MSSQL 和 TiDB(实验性支持) 数据库
+- 支持 MySQL、PostgreSQL、SQLite3、MSSQL 和 TiDB(MySQL) 数据库
 - 支持多语言本地化(21 种语言)
 
 ## 系统要求
diff --git a/docs/content/page/index.zh-tw.md b/docs/content/page/index.zh-tw.md
index 488dac16ad..e475f6f214 100644
--- a/docs/content/page/index.zh-tw.md
+++ b/docs/content/page/index.zh-tw.md
@@ -69,7 +69,7 @@ Gitea 是從 [Gogs](http://gogs.io) Fork 出來的,請閱讀部落格文章 [G
     - PostgreSQL
     - SQLite3
     - MSSQL
-    - TiDB(實驗中, 不建議使用)
+    - TiDB(MySQL 協議)
   - 設定檔
     - [app.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini)
   - 管理員面板
diff --git a/models/engine_test.go b/models/engine_test.go
index 75c854b185..6f4d114db3 100644
--- a/models/engine_test.go
+++ b/models/engine_test.go
@@ -28,8 +28,7 @@ func TestDumpDatabase(t *testing.T) {
 	}
 	assert.NoError(t, db.GetEngine(db.DefaultContext).Sync2(new(Version)))
 
-	for _, dbName := range setting.SupportedDatabases {
-		dbType := setting.GetDBTypeByName(dbName)
+	for _, dbType := range setting.SupportedDatabaseTypes {
 		assert.NoError(t, db.DumpDatabase(filepath.Join(dir, dbType+".sql"), dbType))
 	}
 }
diff --git a/modules/setting/database.go b/modules/setting/database.go
index 02b5e43f4a..8db1cd13eb 100644
--- a/modules/setting/database.go
+++ b/modules/setting/database.go
@@ -16,9 +16,10 @@ import (
 )
 
 var (
-	// SupportedDatabases includes all supported databases type
-	SupportedDatabases = []string{"MySQL", "PostgreSQL", "MSSQL"}
-	dbTypes            = map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3"}
+	// SupportedDatabaseTypes includes all XORM supported databases type, sqlite3 maybe added by `database_sqlite3.go`
+	SupportedDatabaseTypes = []string{"mysql", "postgres", "mssql"}
+	// DatabaseTypeNames contains the friendly names for all database types
+	DatabaseTypeNames = map[string]string{"mysql": "MySQL", "postgres": "PostgreSQL", "mssql": "MSSQL", "sqlite3": "SQLite3"}
 
 	// EnableSQLite3 use SQLite3, set by build flag
 	EnableSQLite3 bool
@@ -52,11 +53,6 @@ var (
 	}
 )
 
-// GetDBTypeByName returns the database type as it defined on XORM according the given name
-func GetDBTypeByName(name string) string {
-	return dbTypes[name]
-}
-
 // InitDBConfig loads the database settings
 func InitDBConfig() {
 	sec := Cfg.Section("database")
diff --git a/modules/setting/database_sqlite.go b/modules/setting/database_sqlite.go
index 798292fec8..12c60cc86c 100644
--- a/modules/setting/database_sqlite.go
+++ b/modules/setting/database_sqlite.go
@@ -13,5 +13,5 @@ import (
 
 func init() {
 	EnableSQLite3 = true
-	SupportedDatabases = append(SupportedDatabases, "SQLite3")
+	SupportedDatabaseTypes = append(SupportedDatabaseTypes, "sqlite3")
 }
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 772189b0ae..b1f8b7994b 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -124,7 +124,7 @@ license_desc = Go get <a target="_blank" rel="noopener noreferrer" href="https:/
 install = Installation
 title = Initial Configuration
 docker_helper = If you run Gitea inside Docker, please read the <a target="_blank" rel="noopener noreferrer" href="%s">documentation</a> before changing any settings.
-requite_db_desc = Gitea requires MySQL, PostgreSQL, MSSQL or SQLite3.
+require_db_desc = Gitea requires MySQL, PostgreSQL, MSSQL, SQLite3 or TiDB (MySQL protocol).
 db_title = Database Settings
 db_type = Database Type
 host = Host
diff --git a/routers/install/install.go b/routers/install/install.go
index b2f04b14dd..45804acf3b 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -42,6 +42,16 @@ const (
 	tplPostInstall base.TplName = "post-install"
 )
 
+var supportedDbTypeNames []map[string]string // use a slice to keep order
+func getDbTypeNames() []map[string]string {
+	if supportedDbTypeNames == nil {
+		for _, t := range setting.SupportedDatabaseTypes {
+			supportedDbTypeNames = append(supportedDbTypeNames, map[string]string{"type": t, "name": setting.DatabaseTypeNames[t]})
+		}
+	}
+	return supportedDbTypeNames
+}
+
 // Init prepare for rendering installation page
 func Init(next http.Handler) http.Handler {
 	var rnd = templates.HTMLRenderer()
@@ -63,7 +73,7 @@ func Init(next http.Handler) http.Handler {
 			Data: map[string]interface{}{
 				"Title":         locale.Tr("install.install"),
 				"PageIsInstall": true,
-				"DbOptions":     setting.SupportedDatabases,
+				"DbTypeNames":   getDbTypeNames(),
 				"i18n":          locale,
 				"Language":      locale.Language(),
 				"Lang":          locale.Language(),
@@ -100,19 +110,18 @@ func Install(ctx *context.Context) {
 	form.DbSchema = setting.Database.Schema
 	form.Charset = setting.Database.Charset
 
-	var curDBOption = "MySQL"
-	switch setting.Database.Type {
-	case "postgres":
-		curDBOption = "PostgreSQL"
-	case "mssql":
-		curDBOption = "MSSQL"
-	case "sqlite3":
-		if setting.EnableSQLite3 {
-			curDBOption = "SQLite3"
+	curDBType := setting.Database.Type
+	var isCurDBTypeSupported bool
+	for _, dbType := range setting.SupportedDatabaseTypes {
+		if dbType == curDBType {
+			isCurDBTypeSupported = true
+			break
 		}
 	}
-
-	ctx.Data["CurDbOption"] = curDBOption
+	if !isCurDBTypeSupported {
+		curDBType = "mysql"
+	}
+	ctx.Data["CurDbType"] = curDBType
 
 	// Application general settings
 	form.AppName = setting.AppName
@@ -237,7 +246,7 @@ func SubmitInstall(ctx *context.Context) {
 		form.AppURL += "/"
 	}
 
-	ctx.Data["CurDbOption"] = form.DbType
+	ctx.Data["CurDbType"] = form.DbType
 
 	if ctx.HasError() {
 		if ctx.HasValue("Err_SMTPUser") {
@@ -261,7 +270,7 @@ func SubmitInstall(ctx *context.Context) {
 	// ---- Basic checks are passed, now test configuration.
 
 	// Test database setting.
-	setting.Database.Type = setting.GetDBTypeByName(form.DbType)
+	setting.Database.Type = form.DbType
 	setting.Database.Host = form.DbHost
 	setting.Database.User = form.DbUser
 	setting.Database.Passwd = form.DbPasswd
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index b419d04a1b..2a27baf535 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -119,7 +119,7 @@
 			<dl class="dl-horizontal admin-dl-horizontal">
 				<dt>{{.i18n.Tr "admin.config.db_type"}}</dt>
 				<dd>{{.DbCfg.Type}}</dd>
-				{{if not (or (eq .DbCfg.Type "sqlite3") (eq .DbCfg.Type "tidb"))}}
+				{{if not (eq .DbCfg.Type "sqlite3")}}
 					<dt>{{.i18n.Tr "admin.config.db_host"}}</dt>
 					<dd>{{if .DbCfg.Host}}{{.DbCfg.Host}}{{else}}-{{end}}</dd>
 					<dt>{{.i18n.Tr "admin.config.db_name"}}</dt>
@@ -133,7 +133,7 @@
 					<dt>{{.i18n.Tr "admin.config.db_ssl_mode"}}</dt>
 					<dd>{{if .DbCfg.SSLMode}}{{.DbCfg.SSLMode}}{{else}}-{{end}}</dd>
 				{{end}}
-				{{if or (eq .DbCfg.Type "sqlite3") (eq .DbCfg.Type "tidb")}}
+				{{if eq .DbCfg.Type "sqlite3"}}
 					<dt>{{.i18n.Tr "admin.config.db_path"}}</dt>
 					<dd>{{if .DbCfg.Path}}{{.DbCfg.Path}}{{else}}-{{end}}</dd>
 				{{end}}
diff --git a/templates/install.tmpl b/templates/install.tmpl
index 1fa0929afa..3c619e880c 100644
--- a/templates/install.tmpl
+++ b/templates/install.tmpl
@@ -13,22 +13,22 @@
 				<form class="ui form" action="{{AppSubUrl}}/" method="post">
 					<!-- Database Settings -->
 					<h4 class="ui dividing header">{{.i18n.Tr "install.db_title"}}</h4>
-					<p>{{.i18n.Tr "install.requite_db_desc"}}</p>
+					<p>{{.i18n.Tr "install.require_db_desc"}}</p>
 					<div class="inline required field {{if .Err_DbType}}error{{end}}">
 						<label>{{.i18n.Tr "install.db_type"}}</label>
 						<div class="ui selection database type dropdown">
-							<input type="hidden" id="db_type" name="db_type" value="{{.CurDbOption}}">
-							<div class="text">{{.CurDbOption}}</div>
+							<input type="hidden" id="db_type" name="db_type" value="{{.CurDbType}}">
+							<div class="text">{{.CurDbType}}</div>
 							{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 							<div class="menu">
-								{{range .DbOptions}}
-									<div class="item" data-value="{{.}}">{{.}}</div>
+								{{range .DbTypeNames}}
+									<div class="item" data-value="{{.type}}">{{.name}}</div>
 								{{end}}
 							</div>
 						</div>
 					</div>
 
-					<div id="sql_settings" class="{{if or (eq .CurDbOption "SQLite3")}}hide{{end}}">
+					<div class="hide" data-db-setting-for="common-host">
 						<div class="inline required field {{if .Err_DbSetting}}error{{end}}">
 							<label for="db_host">{{.i18n.Tr "install.host"}}</label>
 							<input id="db_host" name="db_host" value="{{.db_host}}">
@@ -48,7 +48,7 @@
 						</div>
 					</div>
 
-					<div id="pgsql_settings" class="{{if not (eq .CurDbOption "PostgreSQL")}}hide{{end}}">
+					<div class="hide" data-db-setting-for="postgres">
 						<div class="inline required field">
 							<label>{{.i18n.Tr "install.ssl_mode"}}</label>
 							<div class="ui selection database type dropdown">
@@ -69,7 +69,7 @@
 						</div>
 					</div>
 
-					<div id="mysql_settings" class="{{if not (eq .CurDbOption "MySQL")}}hide{{end}}">
+					<div class="hide" data-db-setting-for="mysql">
 						<div class="inline required field">
 							<label>{{.i18n.Tr "install.charset"}}</label>
 							<div class="ui selection database type dropdown">
@@ -83,7 +83,7 @@
 						</div>
 					</div>
 
-					<div id="sqlite_settings" class="{{if not (or (eq .CurDbOption "SQLite3") (eq .CurDbOption "TiDB"))}}hide{{end}}">
+					<div class="hide" data-db-setting-for="sqlite3">
 						<div class="inline required field {{if or .Err_DbPath .Err_DbSetting}}error{{end}}">
 							<label for="db_path">{{.i18n.Tr "install.path"}}</label>
 							<input id="db_path" name="db_path" value="{{.db_path}}">
diff --git a/web_src/js/features/install.js b/web_src/js/features/install.js
index 6083fa7a58..05e0f9f463 100644
--- a/web_src/js/features/install.js
+++ b/web_src/js/features/install.js
@@ -1,50 +1,41 @@
 export function initInstall() {
-  if ($('.install').length === 0) {
+  if ($('.page-content.install').length === 0) {
     return;
   }
 
-  if ($('#db_host').val() === '') {
-    $('#db_host').val('127.0.0.1:3306');
-    $('#db_user').val('gitea');
-    $('#db_name').val('gitea');
-  }
+  const defaultDbUser = 'gitea';
+  const defaultDbName = 'gitea';
+
+  const defaultDbHosts = {
+    mysql: '127.0.0.1:3306',
+    postgres: '127.0.0.1:5432',
+    mssql: '127.0.0.1:1433'
+  };
+
+  const $dbHost = $('#db_host');
+  const $dbUser = $('#db_user');
+  const $dbName = $('#db_name');
 
   // Database type change detection.
   $('#db_type').on('change', function () {
-    const sqliteDefault = 'data/gitea.db';
-    const tidbDefault = 'data/gitea_tidb';
-
     const dbType = $(this).val();
-    if (dbType === 'SQLite3') {
-      $('#sql_settings').hide();
-      $('#pgsql_settings').hide();
-      $('#mysql_settings').hide();
-      $('#sqlite_settings').show();
+    $('div[data-db-setting-for]').hide();
+    $(`div[data-db-setting-for=${dbType}]`).show();
 
-      if (dbType === 'SQLite3' && $('#db_path').val() === tidbDefault) {
-        $('#db_path').val(sqliteDefault);
+    if (dbType !== 'sqlite3') {
+      // for most remote database servers
+      $(`div[data-db-setting-for=common-host]`).show();
+      const lastDbHost = $dbHost.val();
+      const isDbHostDefault = !lastDbHost || Object.values(defaultDbHosts).includes(lastDbHost);
+      if (isDbHostDefault) {
+        $dbHost.val(defaultDbHosts[dbType] ?? '');
       }
-      return;
-    }
-
-    const dbDefaults = {
-      MySQL: '127.0.0.1:3306',
-      PostgreSQL: '127.0.0.1:5432',
-      MSSQL: '127.0.0.1:1433'
-    };
-
-    $('#sqlite_settings').hide();
-    $('#sql_settings').show();
-
-    $('#pgsql_settings').toggle(dbType === 'PostgreSQL');
-    $('#mysql_settings').toggle(dbType === 'MySQL');
-    $.each(dbDefaults, (_type, defaultHost) => {
-      if ($('#db_host').val() === defaultHost) {
-        $('#db_host').val(dbDefaults[dbType]);
-        return false;
+      if (!$dbUser.val() && !$dbName.val()) {
+        $dbUser.val(defaultDbUser);
+        $dbName.val(defaultDbName);
       }
-    });
-  });
+    } // else: for SQLite3, the default path is always prepared by backend code (setting)
+  }).trigger('change');
 
   // TODO: better handling of exclusive relations.
   $('#offline-mode input').on('change', function () {
diff --git a/web_src/less/_install.less b/web_src/less/_install.less
index c6d93c514c..5769ef68ba 100644
--- a/web_src/less/_install.less
+++ b/web_src/less/_install.less
@@ -1,4 +1,4 @@
-.install {
+.page-content.install {
   padding-top: 45px;
 
   form {