mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Fix various bugs for "install" page (#23194)
## TLDR * Fix the broken page / broken image problem when click "Install" * Close #20089 * Fix the Password Hash Algorithm display problem for #22942 * Close #23183 * Close #23184 ## Details ### The broken page / broken image problem when click "Install" (Redirect failed after install gitea #23184) Before: when click "install", all new requests will fail, because the server has been restarted. Users just see a broken page with broken images, sometimes the server is not ready but the user would have been redirect to "/user/login" page, then the users see a new broken page (connection refused or something wrong ...) After: only check InstallLock=true for necessary handlers, and sleep for a while before restarting the server, then the browser has enough time to load the "post-install" page. And there is a script to check whether "/user/login" is ready, the user will only be redirected to the login page when the server is ready. ### During new instance setup make 'Gitea Base URL' filled from window.location.origin #20089 If the "app_url" input contains `localhost` (the default value from config), use current window's location href as the `app_url` (aka ROOT_URL) ### Fix the Password Hash Algorithm display problem for "Provide the ability to set password hash algorithm parameters #22942" Before: the UI shows `pbkdf2$50000$50` <details>  </details> After: the UI shows `pbkdf2` <details>  </details> ### GET data: net::ERR_INVALID_URL #23183 Cause by empty `data:` in `<link rel="manifest" href="data:{{.ManifestData}}">` --------- Co-authored-by: Jason Song <i@wolfogre.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
		@@ -41,9 +41,8 @@ var RecommendedHashAlgorithms = []string{
 | 
				
			|||||||
	"pbkdf2_hi",
 | 
						"pbkdf2_hi",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetDefaultPasswordHashAlgorithm will take a provided algorithmName and dealias it to
 | 
					// hashAlgorithmToSpec converts an algorithm name or a specification to a full algorithm specification
 | 
				
			||||||
// a complete algorithm specification.
 | 
					func hashAlgorithmToSpec(algorithmName string) string {
 | 
				
			||||||
func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHashAlgorithm) {
 | 
					 | 
				
			||||||
	if algorithmName == "" {
 | 
						if algorithmName == "" {
 | 
				
			||||||
		algorithmName = DefaultHashAlgorithmName
 | 
							algorithmName = DefaultHashAlgorithmName
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -52,10 +51,26 @@ func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHas
 | 
				
			|||||||
		algorithmName = alias
 | 
							algorithmName = alias
 | 
				
			||||||
		alias, has = aliasAlgorithmNames[algorithmName]
 | 
							alias, has = aliasAlgorithmNames[algorithmName]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return algorithmName
 | 
				
			||||||
	// algorithmName should now be a full algorithm specification
 | 
					}
 | 
				
			||||||
	// e.g. pbkdf2$50000$50 rather than pbdkf2
 | 
					
 | 
				
			||||||
	DefaultHashAlgorithm = Parse(algorithmName)
 | 
					// SetDefaultPasswordHashAlgorithm will take a provided algorithmName and de-alias it to
 | 
				
			||||||
 | 
					// a complete algorithm specification.
 | 
				
			||||||
	return algorithmName, DefaultHashAlgorithm
 | 
					func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHashAlgorithm) {
 | 
				
			||||||
 | 
						algoSpec := hashAlgorithmToSpec(algorithmName)
 | 
				
			||||||
 | 
						// now we get a full specification, e.g. pbkdf2$50000$50 rather than pbdkf2
 | 
				
			||||||
 | 
						DefaultHashAlgorithm = Parse(algoSpec)
 | 
				
			||||||
 | 
						return algoSpec, DefaultHashAlgorithm
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ConfigHashAlgorithm will try to find a "recommended algorithm name" defined by RecommendedHashAlgorithms for config
 | 
				
			||||||
 | 
					// This function is not fast and is only used for the installation page
 | 
				
			||||||
 | 
					func ConfigHashAlgorithm(algorithm string) string {
 | 
				
			||||||
 | 
						algorithm = hashAlgorithmToSpec(algorithm)
 | 
				
			||||||
 | 
						for _, recommAlgo := range RecommendedHashAlgorithms {
 | 
				
			||||||
 | 
							if algorithm == hashAlgorithmToSpec(recommAlgo) {
 | 
				
			||||||
 | 
								return recommAlgo
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return algorithm
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -237,7 +237,6 @@ internal_token_failed = Failed to generate internal token: %v
 | 
				
			|||||||
secret_key_failed = Failed to generate secret key: %v
 | 
					secret_key_failed = Failed to generate secret key: %v
 | 
				
			||||||
save_config_failed = Failed to save configuration: %v
 | 
					save_config_failed = Failed to save configuration: %v
 | 
				
			||||||
invalid_admin_setting = Administrator account setting is invalid: %v
 | 
					invalid_admin_setting = Administrator account setting is invalid: %v
 | 
				
			||||||
install_success = Welcome! Thank you for choosing Gitea. Have fun and take care!
 | 
					 | 
				
			||||||
invalid_log_root_path = The log path is invalid: %v
 | 
					invalid_log_root_path = The log path is invalid: %v
 | 
				
			||||||
default_keep_email_private = Hide Email Addresses by Default
 | 
					default_keep_email_private = Hide Email Addresses by Default
 | 
				
			||||||
default_keep_email_private_popup = Hide email addresses of new user accounts by default.
 | 
					default_keep_email_private_popup = Hide email addresses of new user accounts by default.
 | 
				
			||||||
@@ -248,6 +247,7 @@ default_enable_timetracking_popup = Enable time tracking for new repositories by
 | 
				
			|||||||
no_reply_address = Hidden Email Domain
 | 
					no_reply_address = Hidden Email Domain
 | 
				
			||||||
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
 | 
					no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
 | 
				
			||||||
password_algorithm = Password Hash Algorithm
 | 
					password_algorithm = Password Hash Algorithm
 | 
				
			||||||
 | 
					invalid_password_algorithm = Invalid password hash algorithm
 | 
				
			||||||
password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. `argon2` whilst having good characteristics uses a lot of memory and may be inappropriate for small systems.
 | 
					password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. `argon2` whilst having good characteristics uses a lot of memory and may be inappropriate for small systems.
 | 
				
			||||||
enable_update_checker = Enable Update Checker
 | 
					enable_update_checker = Enable Update Checker
 | 
				
			||||||
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
 | 
					enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,11 +59,6 @@ func Init(ctx goctx.Context) func(next http.Handler) http.Handler {
 | 
				
			|||||||
	dbTypeNames := getSupportedDbTypeNames()
 | 
						dbTypeNames := getSupportedDbTypeNames()
 | 
				
			||||||
	return func(next http.Handler) http.Handler {
 | 
						return func(next http.Handler) http.Handler {
 | 
				
			||||||
		return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
 | 
							return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
			if setting.InstallLock {
 | 
					 | 
				
			||||||
				resp.Header().Add("Refresh", "1; url="+setting.AppURL+"user/login")
 | 
					 | 
				
			||||||
				_ = rnd.HTML(resp, http.StatusOK, string(tplPostInstall), nil)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			locale := middleware.Locale(resp, req)
 | 
								locale := middleware.Locale(resp, req)
 | 
				
			||||||
			startTime := time.Now()
 | 
								startTime := time.Now()
 | 
				
			||||||
			ctx := context.Context{
 | 
								ctx := context.Context{
 | 
				
			||||||
@@ -93,6 +88,11 @@ func Init(ctx goctx.Context) func(next http.Handler) http.Handler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Install render installation page
 | 
					// Install render installation page
 | 
				
			||||||
func Install(ctx *context.Context) {
 | 
					func Install(ctx *context.Context) {
 | 
				
			||||||
 | 
						if setting.InstallLock {
 | 
				
			||||||
 | 
							InstallDone(ctx)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	form := forms.InstallForm{}
 | 
						form := forms.InstallForm{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Database settings
 | 
						// Database settings
 | 
				
			||||||
@@ -162,7 +162,7 @@ func Install(ctx *context.Context) {
 | 
				
			|||||||
	form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
 | 
						form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
 | 
				
			||||||
	form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking
 | 
						form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking
 | 
				
			||||||
	form.NoReplyAddress = setting.Service.NoReplyAddress
 | 
						form.NoReplyAddress = setting.Service.NoReplyAddress
 | 
				
			||||||
	form.PasswordAlgorithm = setting.PasswordHashAlgo
 | 
						form.PasswordAlgorithm = hash.ConfigHashAlgorithm(setting.PasswordHashAlgo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	middleware.AssignForm(form, ctx.Data)
 | 
						middleware.AssignForm(form, ctx.Data)
 | 
				
			||||||
	ctx.HTML(http.StatusOK, tplInstall)
 | 
						ctx.HTML(http.StatusOK, tplInstall)
 | 
				
			||||||
@@ -234,6 +234,11 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SubmitInstall response for submit install items
 | 
					// SubmitInstall response for submit install items
 | 
				
			||||||
func SubmitInstall(ctx *context.Context) {
 | 
					func SubmitInstall(ctx *context.Context) {
 | 
				
			||||||
 | 
						if setting.InstallLock {
 | 
				
			||||||
 | 
							InstallDone(ctx)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	form := *web.GetForm(ctx).(*forms.InstallForm)
 | 
						form := *web.GetForm(ctx).(*forms.InstallForm)
 | 
				
			||||||
@@ -277,7 +282,6 @@ func SubmitInstall(ctx *context.Context) {
 | 
				
			|||||||
	setting.Database.Charset = form.Charset
 | 
						setting.Database.Charset = form.Charset
 | 
				
			||||||
	setting.Database.Path = form.DbPath
 | 
						setting.Database.Path = form.DbPath
 | 
				
			||||||
	setting.Database.LogSQL = !setting.IsProd
 | 
						setting.Database.LogSQL = !setting.IsProd
 | 
				
			||||||
	setting.PasswordHashAlgo = form.PasswordAlgorithm
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !checkDatabase(ctx, &form) {
 | 
						if !checkDatabase(ctx, &form) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -499,6 +503,12 @@ func SubmitInstall(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(form.PasswordAlgorithm) > 0 {
 | 
						if len(form.PasswordAlgorithm) > 0 {
 | 
				
			||||||
 | 
							var algorithm *hash.PasswordHashAlgorithm
 | 
				
			||||||
 | 
							setting.PasswordHashAlgo, algorithm = hash.SetDefaultPasswordHashAlgorithm(form.PasswordAlgorithm)
 | 
				
			||||||
 | 
							if algorithm == nil {
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("install.invalid_password_algorithm"), tplInstall, &form)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		cfg.Section("security").Key("PASSWORD_HASH_ALGO").SetValue(form.PasswordAlgorithm)
 | 
							cfg.Section("security").Key("PASSWORD_HASH_ALGO").SetValue(form.PasswordAlgorithm)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -571,18 +581,26 @@ func SubmitInstall(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Info("First-time run install finished!")
 | 
						log.Info("First-time run install finished!")
 | 
				
			||||||
 | 
						InstallDone(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Flash.Success(ctx.Tr("install.install_success"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.RespHeader().Add("Refresh", "1; url="+setting.AppURL+"user/login")
 | 
					 | 
				
			||||||
	ctx.HTML(http.StatusOK, tplPostInstall)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Now get the http.Server from this request and shut it down
 | 
					 | 
				
			||||||
	// NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown
 | 
					 | 
				
			||||||
	srv := ctx.Value(http.ServerContextKey).(*http.Server)
 | 
					 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
 | 
							// Sleep for a while to make sure the user's browser has loaded the post-install page and its assets (images, css, js)
 | 
				
			||||||
 | 
							// What if this duration is not long enough? That's impossible -- if the user can't load the simple page in time, how could they install or use Gitea in the future ....
 | 
				
			||||||
 | 
							time.Sleep(3 * time.Second)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Now get the http.Server from this request and shut it down
 | 
				
			||||||
 | 
							// NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown
 | 
				
			||||||
 | 
							srv := ctx.Value(http.ServerContextKey).(*http.Server)
 | 
				
			||||||
		if err := srv.Shutdown(graceful.GetManager().HammerContext()); err != nil {
 | 
							if err := srv.Shutdown(graceful.GetManager().HammerContext()); err != nil {
 | 
				
			||||||
			log.Error("Unable to shutdown the install server! Error: %v", err)
 | 
								log.Error("Unable to shutdown the install server! Error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// After the HTTP server for "install" shuts down, the `runWeb()` will continue to run the "normal" server
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// InstallDone shows the "post-install" page, makes it easier to develop the page.
 | 
				
			||||||
 | 
					// The name is not called as "PostInstall" to avoid misinterpretation as a handler for "POST /install"
 | 
				
			||||||
 | 
					func InstallDone(ctx *context.Context) { //nolint
 | 
				
			||||||
 | 
						ctx.HTML(http.StatusOK, tplPostInstall)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package install
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	goctx "context"
 | 
						goctx "context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,7 +38,7 @@ func installRecovery(ctx goctx.Context) func(next http.Handler) http.Handler {
 | 
				
			|||||||
				// Why we need this? The first recover will try to render a beautiful
 | 
									// Why we need this? The first recover will try to render a beautiful
 | 
				
			||||||
				// error page for user, but the process can still panic again, then
 | 
									// error page for user, but the process can still panic again, then
 | 
				
			||||||
				// we have to just recover twice and send a simple error page that
 | 
									// we have to just recover twice and send a simple error page that
 | 
				
			||||||
				// should not panic any more.
 | 
									// should not panic anymore.
 | 
				
			||||||
				defer func() {
 | 
									defer func() {
 | 
				
			||||||
					if err := recover(); err != nil {
 | 
										if err := recover(); err != nil {
 | 
				
			||||||
						combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, log.Stack(2))
 | 
											combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, log.Stack(2))
 | 
				
			||||||
@@ -107,8 +108,9 @@ func Routes(ctx goctx.Context) *web.Route {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	r.Use(installRecovery(ctx))
 | 
						r.Use(installRecovery(ctx))
 | 
				
			||||||
	r.Use(Init(ctx))
 | 
						r.Use(Init(ctx))
 | 
				
			||||||
	r.Get("/", Install)
 | 
						r.Get("/", Install) // it must be on the root, because the "install.js" use the window.location to replace the "localhost" AppURL
 | 
				
			||||||
	r.Post("/", web.Bind(forms.InstallForm{}), SubmitInstall)
 | 
						r.Post("/", web.Bind(forms.InstallForm{}), SubmitInstall)
 | 
				
			||||||
 | 
						r.Get("/post-install", InstallDone)
 | 
				
			||||||
	r.Get("/api/healthz", healthcheck.Check)
 | 
						r.Get("/api/healthz", healthcheck.Check)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r.NotFound(web.Wrap(installNotFound))
 | 
						r.NotFound(web.Wrap(installNotFound))
 | 
				
			||||||
@@ -116,5 +118,10 @@ func Routes(ctx goctx.Context) *web.Route {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func installNotFound(w http.ResponseWriter, req *http.Request) {
 | 
					func installNotFound(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
	http.Redirect(w, req, setting.AppURL, http.StatusFound)
 | 
						w.Header().Add("Content-Type", "text/html; charset=utf-8")
 | 
				
			||||||
 | 
						w.Header().Add("Refresh", fmt.Sprintf("1; url=%s", setting.AppSubURL+"/"))
 | 
				
			||||||
 | 
						// do not use 30x status, because the "post-install" page needs to use 404/200 to detect if Gitea has been installed.
 | 
				
			||||||
 | 
						// the fetch API could follow 30x requests to the page with 200 status.
 | 
				
			||||||
 | 
						w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
 | 
						_, _ = fmt.Fprintf(w, `Not Found. <a href="%s">Go to default page</a>.`, html.EscapeString(setting.AppSubURL+"/"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
	<meta charset="utf-8">
 | 
						<meta charset="utf-8">
 | 
				
			||||||
	<meta name="viewport" content="width=device-width, initial-scale=1">
 | 
						<meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
	<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
 | 
						<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
 | 
				
			||||||
	<link rel="manifest" href="data:{{.ManifestData}}">
 | 
						{{if .ManifestData}}<link rel="manifest" href="data:{{.ManifestData}}">{{end}}
 | 
				
			||||||
	<meta name="theme-color" content="{{ThemeColorMetaTag}}">
 | 
						<meta name="theme-color" content="{{ThemeColorMetaTag}}">
 | 
				
			||||||
	<meta name="default-theme" content="{{DefaultTheme}}">
 | 
						<meta name="default-theme" content="{{DefaultTheme}}">
 | 
				
			||||||
	<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}">
 | 
						<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
{{template "base/head" .}}
 | 
					{{template "base/head" .}}
 | 
				
			||||||
<div role="main" aria-label="{{.Title}}" class="page-content install">
 | 
					<div role="main" aria-label="{{.Title}}" class="page-content install post-install">
 | 
				
			||||||
	<div class="ui container">
 | 
						<div class="ui container">
 | 
				
			||||||
		<div class="ui grid">
 | 
							<div class="ui grid">
 | 
				
			||||||
			<div class="sixteen wide column content">
 | 
								<div class="sixteen wide column content">
 | 
				
			||||||
@@ -13,7 +13,7 @@
 | 
				
			|||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					<div class="ui stackable middle very relaxed page grid">
 | 
										<div class="ui stackable middle very relaxed page grid">
 | 
				
			||||||
						<div class="sixteen wide center aligned centered column">
 | 
											<div class="sixteen wide center aligned centered column">
 | 
				
			||||||
							<p><a href="{{AppSubUrl}}/user/login">{{AppSubUrl}}/user/login</a></p>
 | 
												<p><a id="goto-user-login" href="{{AppSubUrl}}/user/login">{{.locale.Tr "loading"}}</a></p>
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,18 @@ import $ from 'jquery';
 | 
				
			|||||||
import {hideElem, showElem} from '../utils/dom.js';
 | 
					import {hideElem, showElem} from '../utils/dom.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function initInstall() {
 | 
					export function initInstall() {
 | 
				
			||||||
  if ($('.page-content.install').length === 0) {
 | 
					  const $page = $('.page-content.install');
 | 
				
			||||||
 | 
					  if ($page.length === 0) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if ($page.is('.post-install')) {
 | 
				
			||||||
 | 
					    initPostInstall();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    initPreInstall();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function initPreInstall() {
 | 
				
			||||||
  const defaultDbUser = 'gitea';
 | 
					  const defaultDbUser = 'gitea';
 | 
				
			||||||
  const defaultDbName = 'gitea';
 | 
					  const defaultDbName = 'gitea';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,6 +48,18 @@ export function initInstall() {
 | 
				
			|||||||
    } // else: for SQLite3, the default path is always prepared by backend code (setting)
 | 
					    } // else: for SQLite3, the default path is always prepared by backend code (setting)
 | 
				
			||||||
  }).trigger('change');
 | 
					  }).trigger('change');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const $appUrl = $('#app_url');
 | 
				
			||||||
 | 
					  const configAppUrl = $appUrl.val();
 | 
				
			||||||
 | 
					  if (configAppUrl.includes('://localhost')) {
 | 
				
			||||||
 | 
					    $appUrl.val(window.location.href);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const $domain = $('#domain');
 | 
				
			||||||
 | 
					  const configDomain = $domain.val().trim();
 | 
				
			||||||
 | 
					  if (configDomain === 'localhost') {
 | 
				
			||||||
 | 
					    $domain.val(window.location.hostname);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: better handling of exclusive relations.
 | 
					  // TODO: better handling of exclusive relations.
 | 
				
			||||||
  $('#offline-mode input').on('change', function () {
 | 
					  $('#offline-mode input').on('change', function () {
 | 
				
			||||||
    if ($(this).is(':checked')) {
 | 
					    if ($(this).is(':checked')) {
 | 
				
			||||||
@@ -83,3 +103,20 @@ export function initInstall() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function initPostInstall() {
 | 
				
			||||||
 | 
					  const el = document.getElementById('goto-user-login');
 | 
				
			||||||
 | 
					  if (!el) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const targetUrl = el.getAttribute('href');
 | 
				
			||||||
 | 
					  let tid = setInterval(async () => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const resp = await fetch(targetUrl);
 | 
				
			||||||
 | 
					      if (tid && resp.status === 200) {
 | 
				
			||||||
 | 
					        clearInterval(tid);
 | 
				
			||||||
 | 
					        tid = null;
 | 
				
			||||||
 | 
					        window.location.href = targetUrl;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch {}
 | 
				
			||||||
 | 
					  }, 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user