Modified - [install] [reinstall] [modal] [app-ini-import] [secrets] Reworked the installer recovery flow around existing databases and imported app.ini secrets.
- 1 - Compared to the previous project state, the installer no longer mixes the existing-database reinstall warning into the main page body and instead runs that confirmation flow in a dedicated modal with the warning content grouped at the top, a `Back` exit path, and an `Install %s` action that stays disabled until all required confirmations are checked; in the same recovery-oriented flow, importing `app.ini` now comes back with `Import sensitive secrets from app.ini` enabled by default, preserves the imported secret values in the form, and keeps the derived site-name label for the install action stable during validation rerenders.
This commit is contained in:
@@ -873,3 +873,6 @@ History search guidance:
|
||||
|
||||
180 - [2026-05-23 05:05:14] - v1.27.0-dev-192-g26e30f5ac2 - Type: Added - [org] [settings] [repository] [adopt] Added an organization-scoped pre-existing repository adoption flow under organization settings.
|
||||
- 1 - I added `routers/web/org/setting_repos.go`, `templates/org/settings/repos.tmpl`, `templates/org/settings/navbar.tmpl`, and the corresponding route wiring in `routers/web/web.go`, then aligned the user and organization repository settings pages so both now separate normal adopted repositories from `Unadopted Repositories`; the final organization implementation correctly resolves adopted repos by `OwnerID`, preventing newly adopted organization repositories from lingering in the unadopted list.
|
||||
|
||||
181 - [2026-05-23 21:45:53] - v1.27.0-dev-193-g66093c1564 - Type: Modified - [install] [reinstall] [modal] [app-ini-import] [secrets] Reworked the installer recovery flow around existing databases and imported `app.ini` secrets.
|
||||
- 1 - Compared to the previous project state, the installer no longer mixes the existing-database reinstall warning into the main page body and instead runs that confirmation flow in a dedicated modal with the warning content grouped at the top, a `Back` exit path, and an `Install %s` action that stays disabled until all required confirmations are checked; in the same recovery-oriented flow, importing `app.ini` now comes back with `Import sensitive secrets from app.ini` enabled by default, preserves the imported secret values in the form, and keeps the derived site-name label for the install action stable during validation rerenders.
|
||||
|
||||
@@ -651,7 +651,7 @@ func ImportAppINI(ctx *context.Context) {
|
||||
}
|
||||
|
||||
form, curDBType := newInstallFormFromSettings()
|
||||
form.ImportSensitiveSecrets = ctx.FormBool("import_sensitive_secrets")
|
||||
form.ImportSensitiveSecrets = true // edit/add - by petru @ codex
|
||||
form.ImportedAppINI = true // edit/add - by petru @ codex
|
||||
cfg, err := readImportedInstallConfig(ctx)
|
||||
if err != nil {
|
||||
@@ -942,6 +942,7 @@ func SubmitInstall(ctx *context.Context) {
|
||||
form.DefaultLanguage = strings.TrimSpace(form.DefaultLanguage)
|
||||
normalizeInstallRegistrationOptions(&form)
|
||||
populateInstallSMTPFromFields(&form)
|
||||
ctx.Data["InstallerSiteName"] = installMailerDisplayName(form.AppName) // edit/add - by petru @ codex
|
||||
|
||||
if form.DefaultLanguage == "" {
|
||||
form.DefaultLanguage = resolveInstallDefaultLanguage("")
|
||||
|
||||
@@ -361,6 +361,43 @@ JWT_SECRET = oauth-secret
|
||||
assert.Contains(t, w.Body.String(), `name="imported_o_auth2_jwt_secret" value="oauth-secret"`)
|
||||
}
|
||||
|
||||
// start edit/add - by petru @ codex
|
||||
func TestImportAppINIDefaultsSensitiveSecretsToEnabled(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.InstallLock, false)()
|
||||
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
|
||||
fileWriter, err := writer.CreateFormFile("app_ini_file", "app.ini")
|
||||
require.NoError(t, err)
|
||||
_, err = fileWriter.Write([]byte(`
|
||||
[server]
|
||||
LFS_JWT_SECRET = lfs-secret
|
||||
|
||||
[security]
|
||||
INTERNAL_TOKEN = internal-secret
|
||||
|
||||
[oauth2]
|
||||
JWT_SECRET = oauth-secret
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, writer.Close())
|
||||
|
||||
r := Routes()
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPost, "/import_app_ini", &body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Contains(t, w.Body.String(), `id="import_sensitive_secrets" name="import_sensitive_secrets" type="checkbox" checked`)
|
||||
assert.Contains(t, w.Body.String(), `name="imported_lfs_jwt_secret" value="lfs-secret"`)
|
||||
assert.Contains(t, w.Body.String(), `name="imported_internal_token" value="internal-secret"`)
|
||||
assert.Contains(t, w.Body.String(), `name="imported_o_auth2_jwt_secret" value="oauth-secret"`)
|
||||
}
|
||||
|
||||
// end edit/add - by petru @ codex
|
||||
|
||||
func TestApplyInstallSensitiveSecretsToConfigPersistsImportedValues(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "app.ini")
|
||||
|
||||
+72
-30
@@ -6,11 +6,11 @@
|
||||
{{ctx.Locale.Tr "install.title"}}
|
||||
</h3>
|
||||
<div class="ui attached segment">
|
||||
{{template "base/alert" .}}
|
||||
{{if not .Err_DbInstalledBefore}}{{template "base/alert" .}}{{end}} <!-- edit/add - by petru @ codex -->
|
||||
|
||||
<p>{{ctx.Locale.Tr "install.docker_helper" "https://docs.gitea.com/installation/install-with-docker"}}</p>
|
||||
|
||||
<form class="ui form js-install-form" action="{{AppSubUrl}}/" method="post" enctype="multipart/form-data">
|
||||
<form id="install-form" class="ui form js-install-form" action="{{AppSubUrl}}/" method="post" enctype="multipart/form-data"> <!-- edit/add - by petru @ codex -->
|
||||
<h4 class="ui dividing header">{{ctx.Locale.Tr "install.import_app_ini_title"}}</h4>
|
||||
<p>{{ctx.Locale.Tr "install.import_app_ini_desc"}}</p>
|
||||
<div class="inline field">
|
||||
@@ -97,30 +97,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if .Err_DbInstalledBefore}}
|
||||
<div>
|
||||
<p class="reinstall-message">{{ctx.Locale.Tr "install.reinstall_confirm_message"}}</p>
|
||||
<div class="reinstall-confirm">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "install.reinstall_confirm_check_1"}}</label>
|
||||
<input name="reinstall_confirm_first" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="reinstall-confirm">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "install.reinstall_confirm_check_2"}}</label>
|
||||
<input name="reinstall_confirm_second" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="reinstall-confirm">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "install.reinstall_confirm_check_3"}}</label>
|
||||
<input name="reinstall_confirm_third" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- General Settings -->
|
||||
<h4 class="ui dividing header">{{ctx.Locale.Tr "install.general_title"}}</h4>
|
||||
<div class="inline required field {{if .Err_AppName}}error{{end}}">
|
||||
@@ -529,18 +505,58 @@
|
||||
{{$filePath := HTMLFormat `<span class="ui label">%s</span> <button class="btn interact-fg" data-clipboard-text="%s">%s</button>` .CustomConfFile .CustomConfFile $copyBtn}}
|
||||
{{ctx.Locale.Tr "install.config_write_file_prompt" $filePath}}
|
||||
</div>
|
||||
{{if not .Err_DbInstalledBefore}} <!-- edit/add - by petru @ codex -->
|
||||
<div class="tw-mt-4 tw-mb-2 tw-text-center">
|
||||
<button
|
||||
class="ui primary button js-install-confirm-button"
|
||||
data-install-label-template="{{ctx.Locale.Tr "install.install_btn_confirm" "__SITE_NAME__"}}"
|
||||
>{{ctx.Locale.Tr "install.install_btn_confirm" .InstallerSiteName}}</button>
|
||||
</div>
|
||||
{{end}} <!-- edit/add - by petru @ codex -->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{if .Err_DbInstalledBefore}}
|
||||
<!-- start edit/add - by petru @ codex -->
|
||||
<div class="ui small modal install-reinstall-confirm-modal js-install-reinstall-modal">
|
||||
<div class="ui negative message install-reinstall-alert">{{ctx.Locale.Tr "install.reinstall_error"}}</div>
|
||||
<div class="content">
|
||||
<p class="reinstall-message">{{ctx.Locale.Tr "install.reinstall_confirm_message"}}</p>
|
||||
<div class="reinstall-confirm">
|
||||
<div class="ui checkbox">
|
||||
<input id="reinstall_confirm_first" name="reinstall_confirm_first" type="checkbox" form="install-form">
|
||||
<label for="reinstall_confirm_first">{{ctx.Locale.Tr "install.reinstall_confirm_check_1"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reinstall-confirm">
|
||||
<div class="ui checkbox">
|
||||
<input id="reinstall_confirm_second" name="reinstall_confirm_second" type="checkbox" form="install-form">
|
||||
<label for="reinstall_confirm_second">{{ctx.Locale.Tr "install.reinstall_confirm_check_2"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reinstall-confirm">
|
||||
<div class="ui checkbox">
|
||||
<input id="reinstall_confirm_third" name="reinstall_confirm_third" type="checkbox" form="install-form">
|
||||
<label for="reinstall_confirm_third">{{ctx.Locale.Tr "install.reinstall_confirm_check_3"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="ui button cancel" href="{{AppSubUrl}}/">{{ctx.Locale.Tr "go_back"}}</a>
|
||||
<button
|
||||
type="submit"
|
||||
form="install-form"
|
||||
class="ui primary button js-install-confirm-button"
|
||||
data-install-label-template="{{ctx.Locale.Tr "install.install_btn_confirm" "__SITE_NAME__"}}"
|
||||
disabled
|
||||
>{{ctx.Locale.Tr "install.install_btn_confirm" .InstallerSiteName}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end edit/add - by petru @ codex -->
|
||||
{{end}}
|
||||
<div class="install-language-balloon" id="install-language-balloon" role="status" aria-live="polite">
|
||||
{{ctx.Locale.Tr "install.language_balloon"}}
|
||||
</div>
|
||||
@@ -670,7 +686,7 @@
|
||||
const installForm = document.querySelector('.js-install-form');
|
||||
const appNameInput = installForm?.querySelector('#app_name');
|
||||
const smtpFromNameInput = installForm?.querySelector('#smtp_from_name');
|
||||
const installConfirmButton = installForm?.querySelector('.js-install-confirm-button');
|
||||
const installConfirmButtons = installForm ? installForm.querySelectorAll('.js-install-confirm-button') : [];
|
||||
if (appNameInput instanceof HTMLInputElement && smtpFromNameInput instanceof HTMLInputElement) {
|
||||
let lastAutoMailerName = smtpFromNameInput.value.trim() || deriveInstallMailerName(appNameInput.value);
|
||||
const syncInstallBranding = () => {
|
||||
@@ -680,7 +696,8 @@
|
||||
smtpFromNameInput.value = siteName;
|
||||
}
|
||||
lastAutoMailerName = siteName;
|
||||
if (installConfirmButton instanceof HTMLButtonElement) {
|
||||
for (const installConfirmButton of installConfirmButtons) {
|
||||
if (!(installConfirmButton instanceof HTMLButtonElement)) continue;
|
||||
installConfirmButton.textContent = installConfirmButton.dataset.installLabelTemplate.replace('__SITE_NAME__', siteName);
|
||||
}
|
||||
};
|
||||
@@ -688,10 +705,13 @@
|
||||
syncInstallBranding();
|
||||
appNameInput.addEventListener('input', syncInstallBranding);
|
||||
appNameInput.addEventListener('change', syncInstallBranding);
|
||||
} else if (appNameInput instanceof HTMLInputElement && installConfirmButton instanceof HTMLButtonElement) {
|
||||
} else if (appNameInput instanceof HTMLInputElement && installConfirmButtons.length > 0) {
|
||||
const syncInstallButton = () => {
|
||||
const siteName = deriveInstallMailerName(appNameInput.value);
|
||||
installConfirmButton.textContent = installConfirmButton.dataset.installLabelTemplate.replace('__SITE_NAME__', siteName);
|
||||
for (const installConfirmButton of installConfirmButtons) {
|
||||
if (!(installConfirmButton instanceof HTMLButtonElement)) continue;
|
||||
installConfirmButton.textContent = installConfirmButton.dataset.installLabelTemplate.replace('__SITE_NAME__', siteName);
|
||||
}
|
||||
};
|
||||
syncInstallButton();
|
||||
appNameInput.addEventListener('input', syncInstallButton);
|
||||
@@ -742,6 +762,28 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
dismissInstallSuccessFlash();
|
||||
|
||||
{{if .Err_DbInstalledBefore}}
|
||||
// start edit/add - by petru @ codex
|
||||
const reinstallModal = document.querySelector('.js-install-reinstall-modal');
|
||||
if (reinstallModal) {
|
||||
const reinstallConfirmInputs = reinstallModal.querySelectorAll('input[name^="reinstall_confirm_"]');
|
||||
const reinstallConfirmButton = reinstallModal.querySelector('.js-install-confirm-button');
|
||||
const syncReinstallConfirmButton = () => {
|
||||
if (!(reinstallConfirmButton instanceof HTMLButtonElement)) return;
|
||||
reinstallConfirmButton.disabled = [...reinstallConfirmInputs].some((input) => !(input instanceof HTMLInputElement) || !input.checked);
|
||||
};
|
||||
for (const input of reinstallConfirmInputs) {
|
||||
input.addEventListener('change', syncReinstallConfirmButton);
|
||||
}
|
||||
syncReinstallConfirmButton();
|
||||
window.$(reinstallModal).modal({
|
||||
autofocus: false,
|
||||
closable: false,
|
||||
}).modal('show');
|
||||
}
|
||||
// end edit/add - by petru @ codex
|
||||
{{end}}
|
||||
|
||||
const installLanguageBalloon = document.querySelector('#install-language-balloon');
|
||||
const footerLanguageSelector = document.querySelector('#footer-language-selector');
|
||||
if (!installLanguageBalloon || !footerLanguageSelector) return;
|
||||
|
||||
@@ -70,6 +70,57 @@
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
/* start edit/add - by petru @ codex */
|
||||
.page-content.install .install-reinstall-confirm-modal .content {
|
||||
padding-top: 1.25rem;
|
||||
}
|
||||
|
||||
.ui.negative.message.install-reinstall-alert {
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .install-reinstall-alert {
|
||||
margin-bottom: 1rem;
|
||||
text-align: center;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .reinstall-message,
|
||||
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .reinstall-message {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-error-text);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm + .reinstall-confirm {
|
||||
margin-top: 0.6rem;
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm .ui.checkbox label {
|
||||
display: block;
|
||||
padding-left: 1.5rem;
|
||||
line-height: 1.5;
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.page-content.install .install-reinstall-confirm-modal .actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
/* end edit/add - by petru @ codex */
|
||||
|
||||
.install-language-balloon {
|
||||
position: fixed;
|
||||
right: 10.5rem;
|
||||
|
||||
@@ -101,6 +101,10 @@ input[type="checkbox"]:indeterminate::before {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.reinstall-confirm > .ui.checkbox label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ui.checkbox + label {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user