Учёт DEPO: скрипт снова выполняется; логин bj виден в обоих способах; новые логин и пароль — только после проверки входа
- EXEC(...) в T-SQL склеивает только строки и переменные: REPLACE/QUOTENAME внутри давали ошибку 102, и SQL Server отклонял весь скрипт (.06.4–.06.6). Команда входа собирается в @sql заранее; тест ловит вызовы функций внутри EXEC; живая проверка синтаксиса на SQL Server без выполнения (SET PARSEONLY) — TestDepoSetupScriptParseLive. - «Логин bj / Пароль bj» и в способе «Дать логин администратора»: на общем сервере bj_user может быть занят другим bj — подготовка сменила бы ему пароль. Предупреждение. - Показ скрипта на странице ничего не сохраняет. Логин и пароль из выданного скрипта и из «Проверить подключение» хранятся черновиком (DepoNewUser/DepoNewPass) и становятся рабочими только после успешного входа: службы bj с неверным паролем за минуты блокировали логин на сервере (CHECK_POLICY) — у всех, кто им пользуется. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -99,11 +99,14 @@ END
|
||||
PRINT N'База DEPO: ' + @db;
|
||||
DECLARE @in nvarchar(300) = N'USE ' + QUOTENAME(@db) + N'; ';
|
||||
|
||||
-- 1. Логин bj
|
||||
-- 1. Логин bj (если такой логин на сервере уже есть — ему ставится пароль из @pass)
|
||||
-- (EXEC(...) склеивает только строки и переменные — команда собирается в @sql заранее)
|
||||
DECLARE @sql nvarchar(max);
|
||||
IF SUSER_ID(N'%[1]s') IS NULL
|
||||
EXEC(N'CREATE LOGIN [%[1]s] WITH PASSWORD = N''' + REPLACE(@pass, N'''', N'''''') + N''', CHECK_POLICY = ON, DEFAULT_DATABASE = ' + QUOTENAME(@db))
|
||||
SET @sql = N'CREATE LOGIN [%[1]s] WITH PASSWORD = N''' + REPLACE(@pass, N'''', N'''''') + N''', CHECK_POLICY = ON, DEFAULT_DATABASE = ' + QUOTENAME(@db);
|
||||
ELSE
|
||||
EXEC(N'ALTER LOGIN [%[1]s] WITH PASSWORD = N''' + REPLACE(@pass, N'''', N'''''') + N'''');
|
||||
SET @sql = N'ALTER LOGIN [%[1]s] WITH PASSWORD = N''' + REPLACE(@pass, N'''', N'''''') + N'''';
|
||||
EXEC(@sql);
|
||||
|
||||
-- 2. Таблицы обмена FTV_M2M* (только недостающие таблицы, колонки и индексы — данные не меняются)
|
||||
`, login, job, sqlStr(db), sqlStr(pass))
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package lkgateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Синтаксис скрипта подготовки DEPO на настоящем SQL Server — без выполнения (SET PARSEONLY ON: сервер только
|
||||
// разбирает текст). BJ_DEPO_PARSE_CFG=<копия setup.json с подключением к DEPO> go test -run TestDepoSetupScriptParseLive.
|
||||
// Для надёжности база в скрипте — заведомо несуществующая: даже без PARSEONLY скрипт остановился бы до изменений.
|
||||
func TestDepoSetupScriptParseLive(t *testing.T) {
|
||||
cfg := os.Getenv("BJ_DEPO_PARSE_CFG")
|
||||
if cfg == "" {
|
||||
t.Skip("BJ_DEPO_PARSE_CFG не задан")
|
||||
}
|
||||
rc, err := NewRuntimeConfig(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f := rc.Snapshot().Fancy
|
||||
if f.IsPostgres() || f.Server == "" {
|
||||
t.Skip("в настройках нет SQL Server DEPO")
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
|
||||
defer cancel()
|
||||
db, err := fancyOpen(f, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
conn, err := db.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if _, err := conn.ExecContext(ctx, "SET PARSEONLY ON"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// режим действует: ошибка, поднятая командой, не возникает — значит, ничего не выполняется
|
||||
if _, err := conn.ExecContext(ctx, "RAISERROR(N'parseonly-probe', 16, 1)"); err != nil {
|
||||
t.Fatalf("SET PARSEONLY не действует — дальше не идём: %s", quikErrorDetail(err))
|
||||
}
|
||||
// и ловит ровно ту ошибку, что была в выпусках .06.4–.06.6: вызов функции внутри EXEC(...)
|
||||
if _, err := conn.ExecContext(ctx, "DECLARE @p nvarchar(10) = N'a'; EXEC(N'SELECT ' + REPLACE(@p, N'a', N'1'))"); err == nil {
|
||||
t.Fatal("разбор не заметил функцию внутри EXEC(...) — проверка ничего не стоит")
|
||||
}
|
||||
const nodb, login, pass = "BJ_PARSE_CHECK_NO_SUCH_DB", "bj_parse_check", "Xk7pQ2mN'9vR4tL8w"
|
||||
for _, agent := range []bool{true, false} {
|
||||
if _, err := conn.ExecContext(ctx, depoSetupScript(f, nodb, login, pass, agent)); err != nil {
|
||||
t.Fatalf("скрипт (задание Agent: %v): %s", agent, quikErrorDetail(err))
|
||||
}
|
||||
}
|
||||
// команды, которые скрипт собирает и выполняет через EXEC, — по отдельности
|
||||
stmts := []string{
|
||||
"CREATE LOGIN [" + login + "] WITH PASSWORD = N'" + sqlStr(pass) + "', CHECK_POLICY = ON, DEFAULT_DATABASE = [" + nodb + "]",
|
||||
"ALTER LOGIN [" + login + "] WITH PASSWORD = N'" + sqlStr(pass) + "'",
|
||||
}
|
||||
stmts = append(stmts, depoTablesDDL(false)...)
|
||||
stmts = append(stmts, depoTablesGrantSQL(false, login)...)
|
||||
for _, q := range stmts {
|
||||
if _, err := conn.ExecContext(ctx, q); err != nil {
|
||||
t.Fatalf("%s → %s", depoStmtHead(q), quikErrorDetail(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,6 +366,15 @@ func TestDepoSetupScript(t *testing.T) {
|
||||
t.Fatalf("нечётные кавычки: %s", line)
|
||||
}
|
||||
}
|
||||
// EXEC(...) в T-SQL склеивает только литералы и переменные: вызов функции внутри (REPLACE, QUOTENAME…) —
|
||||
// ошибка 102 «Неправильный синтаксис», и весь скрипт не выполняется (так было в .06.4–.06.6)
|
||||
for _, sc := range []string{s, depoSetupScript(f, "DEPO_X", "bj_user", "Pass1word", false)} {
|
||||
for _, line := range strings.Split(sc, "\n") {
|
||||
if ln := strings.TrimSpace(line); strings.HasPrefix(ln, "EXEC(") && strings.Contains(tsqlOutsideLiterals(ln[len("EXEC("):]), "(") {
|
||||
t.Fatalf("в EXEC(...) вызов функции — SQL Server не примет: %s", ln)
|
||||
}
|
||||
}
|
||||
}
|
||||
bj := depoSetupScript(f, "DEPO_X", "bj_user", "Pass1word", false)
|
||||
if strings.Contains(bj, "sp_add_job") || !strings.Contains(bj, "GRANT EXECUTE ON dbo.FTV_M2M_JOB") || !strings.Contains(bj, "N'DEPO_X'") {
|
||||
t.Fatal("обработка силами bj: без задания, с правом на процедуру и указанной базой")
|
||||
@@ -460,8 +469,9 @@ func TestDumpFirstRunPage(t *testing.T) {
|
||||
_ = os.WriteFile(filepath.Join(dir, "first-run.html"), []byte(b.String()), 0o644)
|
||||
}
|
||||
|
||||
// «Отдать скрипт администратору»: скрипт показывается на странице с базой и паролем с экрана, пароль
|
||||
// запоминается (с ним bj потом проверяет подключение); короткий пароль не принимается.
|
||||
// «Получить скрипт»: скрипт показывается на странице с базой и паролем с экрана и при показе ничего не
|
||||
// сохраняет; файлом — логин и пароль запоминаются черновиком, рабочие (с ними ходят службы bj) не меняются
|
||||
// до проверки входа: неверный пароль от служб блокирует логин на сервере. Короткий пароль не принимается.
|
||||
func TestDepoScriptView(t *testing.T) {
|
||||
priv := testLicenseKey(t)
|
||||
rc := testRC(t)
|
||||
@@ -488,22 +498,46 @@ func TestDepoScriptView(t *testing.T) {
|
||||
if w.Code != http.StatusOK || !strings.Contains(w.Body.String(), "DECLARE @db sysname = N'DEPO_X';") || !strings.Contains(w.Body.String(), "N'Secret123x';") {
|
||||
t.Fatalf("показ скрипта: %d %s", w.Code, w.Body.String()[:min(300, w.Body.Len())])
|
||||
}
|
||||
if f := rc.Snapshot().Fancy; f.User != "bj_user" || f.Password != "Secret123x" || f.DepoTablesMode != "script" {
|
||||
t.Fatalf("логин и пароль bj не запомнились: %+v", f.User)
|
||||
if f := rc.Snapshot().Fancy; f.Server != "" || f.User != "" || f.DepoNewUser != "" {
|
||||
t.Fatalf("показ скрипта не должен ничего сохранять: %q %q %q", f.Server, f.User, f.DepoNewUser)
|
||||
}
|
||||
// рабочий логин уже есть (другой bj на том же сервере или прежняя настройка) — файл его не трогает
|
||||
cur := rc.Snapshot().Fancy
|
||||
cur.User, cur.Password = "bj_user", "Working1x"
|
||||
if err := rc.UpdateFancy(cur); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
form.Del("view")
|
||||
if w := post(form); w.Code != http.StatusOK || !strings.Contains(w.Header().Get("Content-Disposition"), "attachment") {
|
||||
t.Fatalf("скрипт файлом: %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
if f := rc.Snapshot().Fancy; f.User != "bj_user" || f.Password != "Working1x" || f.DepoNewUser != "bj_user" || f.DepoNewPass != "Secret123x" || f.Server != "10.0.0.5" || f.DepoTablesMode != "script" {
|
||||
t.Fatalf("файл: рабочие логин/пароль должны остаться, новые — черновиком: %q/%q, черновик %q", f.User, f.Password, f.DepoNewUser)
|
||||
}
|
||||
form.Set("view", "1")
|
||||
form.Set("bj_password", "short")
|
||||
if w := post(form); w.Code != http.StatusBadRequest || !strings.Contains(w.Body.String(), "8 знаков") {
|
||||
t.Fatalf("короткий пароль: %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
// экран пересобирает скрипт на ходу — и до того, как вписан адрес сервера; без адреса ничего не сохраняется
|
||||
// «Проверить подключение», а войти не удалось — рабочими остаются прежние логин и пароль
|
||||
chk := url.Values{"server": {"127.0.0.1"}, "port": {"1"}, "db_type": {"mssql"}, "depo_database": {"DEPO_X"},
|
||||
"mode": {"script"}, "bj_user": {"bj_new"}, "bj_password": {"Newpass12"}, "depo_job": {"bj"}}
|
||||
r := httptest.NewRequest(http.MethodPost, "/admin/setup/wizard-depo/setup", strings.NewReader(chk.Encode()))
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
cw := httptest.NewRecorder()
|
||||
h.wizardDepoSetup(cw, r)
|
||||
if loc := cw.Header().Get("Location"); cw.Code != http.StatusSeeOther || !strings.Contains(loc, "flash=") {
|
||||
t.Fatalf("проверка без сервера: %d %s", cw.Code, loc)
|
||||
}
|
||||
if f := rc.Snapshot().Fancy; f.User != "bj_user" || f.Password != "Working1x" || f.DepoNewUser != "bj_new" || f.DepoNewPass != "Newpass12" {
|
||||
t.Fatalf("вход не удался — рабочие логин/пароль не должны меняться: %q/%q, черновик %q", f.User, f.Password, f.DepoNewUser)
|
||||
}
|
||||
// экран пересобирает скрипт на ходу — и до того, как вписан адрес сервера
|
||||
form.Set("bj_password", "Other123x")
|
||||
form.Set("server", "")
|
||||
if w := post(form); w.Code != http.StatusOK || !strings.Contains(w.Body.String(), "N'Other123x';") {
|
||||
t.Fatalf("скрипт без адреса сервера: %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
if f := rc.Snapshot().Fancy; f.Server != "10.0.0.5" || f.Password != "Secret123x" {
|
||||
t.Fatalf("без адреса сервера настройки не должны меняться: %q", f.Server)
|
||||
}
|
||||
// имя базы обязательно (bj по серверу не ищет) — без него вместо скрипта понятная причина
|
||||
form.Set("depo_database", "")
|
||||
if w := post(form); w.Code != http.StatusBadRequest || !strings.Contains(w.Body.String(), "имя базы") {
|
||||
@@ -518,3 +552,24 @@ func TestDepoScriptView(t *testing.T) {
|
||||
t.Fatalf("PostgreSQL: %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// tsqlOutsideLiterals — текст T-SQL без строковых литералов ('…', внутри ” — экранированная кавычка).
|
||||
func tsqlOutsideLiterals(s string) string {
|
||||
var b strings.Builder
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] != '\'' {
|
||||
b.WriteByte(s[i])
|
||||
continue
|
||||
}
|
||||
for i++; i < len(s); i++ {
|
||||
if s[i] == '\'' {
|
||||
if i+1 < len(s) && s[i+1] == '\'' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -211,6 +211,11 @@ type FancyMSSQLSettings struct {
|
||||
DepoTablesCheck string `json:"depo_tables_check"`
|
||||
DepoTablesCheckOK bool `json:"depo_tables_check_ok"`
|
||||
DepoTablesCheckAt time.Time `json:"depo_tables_check_at"`
|
||||
// Логин и пароль bj из выданного скрипта, ещё не проверенные входом. В работу (User/Password) — только
|
||||
// после успешного входа: службы bj ходят в DEPO с рабочими, и неверный пароль от них за минуты блокирует
|
||||
// логин на сервере (CHECK_POLICY) — для всех, кто им пользуется.
|
||||
DepoNewUser string `json:"depo_new_user,omitempty"`
|
||||
DepoNewPass string `json:"depo_new_password,omitempty"`
|
||||
}
|
||||
|
||||
// IsPostgres сообщает, выбран ли PostgreSQL (иначе — MSSQL по умолчанию).
|
||||
|
||||
@@ -324,7 +324,9 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
|
||||
if step == 3 {
|
||||
d.Sub = depoWizardSub(r.URL.Query().Get("sub"))
|
||||
d.DepoUser, d.DepoPass = depoSetupLogin(s.Fancy), s.Fancy.Password
|
||||
if s.Fancy.User != d.DepoUser || d.DepoPass == "" {
|
||||
if s.Fancy.DepoNewUser != "" { // скрипт уже выдан, вход ещё не проверен — те же логин и пароль, что в нём
|
||||
d.DepoUser, d.DepoPass = s.Fancy.DepoNewUser, s.Fancy.DepoNewPass
|
||||
} else if s.Fancy.User != d.DepoUser || d.DepoPass == "" {
|
||||
d.DepoPass = depoGenPassword()
|
||||
}
|
||||
d.DepoMode = "auto"
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
.dq-opt { color:var(--muted); font-weight:400; }
|
||||
.dq-note { color:var(--muted); font-size:13px; margin:8px 0 0; }
|
||||
.dq-panel { margin-top:18px; }
|
||||
.dq-panel + .dq-panel { margin-top:14px; }
|
||||
.wiz-card .dq-go { margin-top:16px; border-radius:999px; padding:10px 22px; font-size:14.5px; font-weight:600; }
|
||||
.wiz-card .dq-mono { font-family:var(--mono); }
|
||||
.dq-sql { margin-top:14px; }
|
||||
@@ -203,19 +204,26 @@
|
||||
|
||||
<div class="dq-panel" id="wiz-depo-auto">
|
||||
<div class="dq-grid dq-2">
|
||||
<label>Логин администратора<input type="text" name="admin_user" autocomplete="off" spellcheck="false" placeholder="{{if $pg}}postgres{{else}}sa{{end}}"></label>
|
||||
<label>Пароль<input type="password" name="admin_password" autocomplete="new-password"></label>
|
||||
<label>Логин администратора SQL<input type="text" name="admin_user" autocomplete="off" spellcheck="false" placeholder="{{if $pg}}postgres{{else}}sa{{end}}"></label>
|
||||
<label>Пароль администратора<input type="password" name="admin_password" autocomplete="new-password"></label>
|
||||
</div>
|
||||
<p class="dq-note">bj создаст свой логин, таблицы обмена<span data-ms> и задание обработки</span>, выдаст права и проверит подключение.</p>
|
||||
<button type="submit" class="btn dq-go">Подготовить</button>
|
||||
</div>
|
||||
|
||||
<div class="dq-panel" id="wiz-depo-script">
|
||||
{{/* логин bj — в обоих способах: на общем сервере SQL bj_user может быть уже занят другим bj */}}
|
||||
<div class="dq-panel" id="wiz-depo-login">
|
||||
<div class="dq-grid dq-2">
|
||||
<label>Логин bj<input type="text" name="bj_user" value="{{.DepoUser}}" autocomplete="off" spellcheck="false"></label>
|
||||
<label>Пароль bj<input type="text" name="bj_password" value="{{.DepoPass}}" autocomplete="off" spellcheck="false" class="dq-mono"></label>
|
||||
</div>
|
||||
<p class="dq-note">Скрипт создаст этот логин — с ним bj будет входить в базу DEPO. Пароль придумал bj, можно вписать свой.</p>
|
||||
<p class="dq-note">С этим логином bj будет входить в базу DEPO — его создаст подготовка. Пароль придумал bj, можно вписать свой. <b>Если такой логин на сервере уже есть, его пароль будет заменён</b> — когда этим логином пользуется другая программа, впишите другое имя.</p>
|
||||
</div>
|
||||
|
||||
<div class="dq-panel" id="wiz-depo-autogo">
|
||||
<p class="dq-note">bj проверит, что это база DEPO, создаст свой логин, таблицы обмена<span data-ms> и задание обработки</span>, выдаст права и проверит подключение.</p>
|
||||
<button type="submit" class="btn dq-go">Подготовить</button>
|
||||
</div>
|
||||
|
||||
<div class="dq-panel" id="wiz-depo-script">
|
||||
<div class="dq-sql">
|
||||
<div class="dq-sql-head copy-bar">
|
||||
<span class="dq-sql-st" id="wiz-depo-st">Скрипт собирается из ответов выше и обновляется сам.</span>
|
||||
@@ -246,7 +254,8 @@
|
||||
f.classList.toggle('is-pg', pg);
|
||||
if(pg&&f.port.value==='1433') f.port.value='5432'; else if(!pg&&f.port.value==='5432') f.port.value='1433';
|
||||
f.admin_user.placeholder=pg?'postgres':'sa';
|
||||
['auto','script','existing'].forEach(function(k){ document.getElementById('wiz-depo-'+k).hidden=m!==k; });
|
||||
var show={auto:['auto','login','autogo'], script:['login','script'], existing:['existing']}[m]||[];
|
||||
['auto','login','autogo','script','existing'].forEach(function(k){ document.getElementById('wiz-depo-'+k).hidden=show.indexOf(k)<0; });
|
||||
}
|
||||
function load(){ // скрипт — из текущих ответов; устаревший ответ (пока печатали дальше) не показываем
|
||||
if(f.mode.value!=='script') return;
|
||||
|
||||
@@ -253,9 +253,10 @@ func depoEnsureLogin(s *FancyMSSQLSettings) {
|
||||
}
|
||||
}
|
||||
|
||||
// depoScriptCreds — логин и пароль bj с экрана «Отдать скрипт администратору» (поля видны и меняются;
|
||||
// пустой пароль — bj придумает сам). Возвращает текст ошибки.
|
||||
func depoScriptCreds(r *http.Request, s *FancyMSSQLSettings) string {
|
||||
// depoBjCreds — логин и пароль bj с экрана подготовки. Видны в обоих способах — «логин администратора» и
|
||||
// «скрипт»: на общем сервере SQL логин bj_user может быть уже занят другим bj (подготовка сменила бы ему
|
||||
// пароль) — тогда вписывают другое имя. Пустой пароль — bj придумает сам. Возвращает текст ошибки.
|
||||
func depoBjCreds(r *http.Request, s *FancyMSSQLSettings) string {
|
||||
if u := strings.TrimSpace(r.FormValue("bj_user")); u != "" {
|
||||
if !depoLoginRe.MatchString(u) {
|
||||
return "логин bj — латинские буквы, цифры, точка, дефис и _"
|
||||
@@ -289,7 +290,7 @@ func (h *setupHandlers) wizardDepoScript(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
s, db, agent, bad := h.depoSetupForm(r)
|
||||
if bad == "" {
|
||||
bad = depoScriptCreds(r, &s)
|
||||
bad = depoBjCreds(r, &s)
|
||||
}
|
||||
if bad != "" {
|
||||
fail(bad)
|
||||
@@ -297,8 +298,10 @@ func (h *setupHandlers) wizardDepoScript(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
depoEnsureLogin(&s)
|
||||
s.DepoTablesMode = "script"
|
||||
if s.Server != "" { // скрипт собирается и до адреса сервера (экран обновляет его на ходу) — без адреса не сохраняем
|
||||
if err := h.rc.UpdateFancy(s); err != nil {
|
||||
// показ на странице (экран пересобирает скрипт на ходу) ничего не сохраняет; файл — уходит администратору:
|
||||
// запомнить логин и пароль из него, но только черновиком — в работу они пойдут после проверки входа
|
||||
if !view && s.Server != "" {
|
||||
if err := h.rc.UpdateFancy(depoDraft(s, h.rc.Snapshot().Fancy)); err != nil {
|
||||
fail("не сохранилось: " + err.Error())
|
||||
return
|
||||
}
|
||||
@@ -318,12 +321,22 @@ func (h *setupHandlers) wizardDepoScript(w http.ResponseWriter, r *http.Request)
|
||||
_, _ = w.Write([]byte(body))
|
||||
}
|
||||
|
||||
// depoDraft — настройки экрана с логином и паролем bj черновиком: рабочими остаются прежние (saved), новые —
|
||||
// в DepoNewUser/DepoNewPass до успешного входа.
|
||||
func depoDraft(s, saved FancyMSSQLSettings) FancyMSSQLSettings {
|
||||
d := s
|
||||
d.User, d.Password = saved.User, saved.Password
|
||||
d.DepoNewUser, d.DepoNewPass = s.User, s.Password
|
||||
return d
|
||||
}
|
||||
|
||||
// wizardDepoSetup — POST /admin/setup/wizard-depo/setup: подготовить базу (mode=auto — bj сам логином
|
||||
// администратора), проверить после скрипта (mode=script) или с готовым логином (mode=existing).
|
||||
func (h *setupHandlers) wizardDepoSetup(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost || !requireDepo(w, r) {
|
||||
return
|
||||
}
|
||||
saved := h.rc.Snapshot().Fancy
|
||||
s, db, agent, bad := h.depoSetupForm(r)
|
||||
if bad == "" && s.Server == "" {
|
||||
bad = "укажите адрес сервера DEPO"
|
||||
@@ -342,6 +355,10 @@ func (h *setupHandlers) wizardDepoSetup(w http.ResponseWriter, r *http.Request)
|
||||
wizDepoGo(w, r, "setup", "введите логин и пароль администратора SQL (они используются один раз и не сохраняются)", false)
|
||||
return
|
||||
}
|
||||
if bad := depoBjCreds(r, &s); bad != "" {
|
||||
wizDepoGo(w, r, "setup", bad, false)
|
||||
return
|
||||
}
|
||||
depoEnsureLogin(&s)
|
||||
if err := depoSetupRun(ctx, s, db, au, r.FormValue("admin_password"), s.User, s.Password, agent); err != nil {
|
||||
wizDepoGo(w, r, "setup", "база не подготовлена — "+err.Error(), false)
|
||||
@@ -363,7 +380,7 @@ func (h *setupHandlers) wizardDepoSetup(w http.ResponseWriter, r *http.Request)
|
||||
s.User, s.Password = u, r.FormValue("password")
|
||||
}
|
||||
default: // script — администратор выполнил скрипт: логин и пароль bj — с экрана (они же в настройках)
|
||||
if bad := depoScriptCreds(r, &s); bad != "" {
|
||||
if bad := depoBjCreds(r, &s); bad != "" {
|
||||
wizDepoGo(w, r, "setup", bad, false)
|
||||
return
|
||||
}
|
||||
@@ -374,7 +391,7 @@ func (h *setupHandlers) wizardDepoSetup(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
s.DepoDatabase = db
|
||||
if err := h.rc.UpdateFancy(s); err != nil {
|
||||
if err := h.rc.UpdateFancy(depoDraft(s, saved)); err != nil {
|
||||
wizDepoGo(w, r, "setup", "не сохранилось: "+err.Error(), false)
|
||||
return
|
||||
}
|
||||
@@ -382,6 +399,11 @@ func (h *setupHandlers) wizardDepoSetup(w http.ResponseWriter, r *http.Request)
|
||||
wizDepoGo(w, r, "setup", note+"войти логином "+s.User+" не удалось — "+quikErrorDetail(err)+". Выполнен ли скрипт на сервере "+s.Server+"?", false)
|
||||
return
|
||||
}
|
||||
s.DepoNewUser, s.DepoNewPass = "", "" // вход проверен — логин и пароль в работу
|
||||
if err := h.rc.UpdateFancy(s); err != nil {
|
||||
wizDepoGo(w, r, "setup", "не сохранилось: "+err.Error(), false)
|
||||
return
|
||||
}
|
||||
if err := depoCheckIsDepo(ctx, s, db); err != nil { // имя базы задал клиент — та ли это база
|
||||
wizDepoGo(w, r, "setup", note+err.Error(), false)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user