package lkgateway // Шаг 3 мастера настройки (учёт DEPO) — маленький мастер по экранам вместо простыни настроек: // описание → подключение → трансферные таблицы → обработка (job) → готово. Каждый экран делает // своё действие по «Далее» и сразу проверяет результат; при ошибке экран не меняется, ошибка // показывается понятным текстом. Полный раздел «Обмен Fancy» остаётся в «Настройке». import ( "context" "net/http" "net/url" "strings" "time" ) // depoWizardSubs — экраны шага 3 по порядку. var depoWizardSubs = []struct{ Key, Title string }{ {"intro", "Что это"}, {"conn", "Подключение"}, {"tables", "Таблицы обмена"}, {"job", "Обработка"}, {"done", "Готово"}, } func depoWizardSub(v string) string { for _, s := range depoWizardSubs { if s.Key == v { return v } } return "intro" } // wizDepoGo — перейти на экран шага 3 с сообщением (ok=false — сообщение об ошибке). func wizDepoGo(w http.ResponseWriter, r *http.Request, sub, msg string, ok bool) { u := "/admin/wizard?step=3&sub=" + sub if msg != "" { if ok { msg = "✓ " + msg } else { msg = "✗ " + msg } u += "&flash=" + url.QueryEscape(msg) } http.Redirect(w, r, u, http.StatusSeeOther) } // wizardDepoConn — POST /admin/setup/wizard-depo/conn: сохранить подключение и сразу проверить его. func (h *setupHandlers) wizardDepoConn(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost || !requireDepo(w, r) { return } s := h.fancyFromForm(r) if db := strings.TrimSpace(r.FormValue("depo_database")); db != "" { if !validDBName(db) { wizDepoGo(w, r, "conn", "имя базы DEPO — только латинские буквы, цифры и _, начинается с буквы", false) return } if db != s.DepoDatabase { s.DepoTablesCheck, s.DepoTablesCheckOK = "", false } s.DepoDatabase = db } if s.Server == "" || s.User == "" { wizDepoGo(w, r, "conn", "укажите адрес сервера и логин", false) return } if err := h.rc.UpdateFancy(s); err != nil { wizDepoGo(w, r, "conn", "не сохранилось: "+err.Error(), false) return } ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second) defer cancel() if _, err := fancyPing(ctx, s, "master"); err != nil { wizDepoGo(w, r, "conn", "к серверу подключиться не удалось — "+err.Error()+". Проверьте адрес, порт, логин и пароль.", false) return } if _, err := fancyPing(ctx, s, s.DepoDB()); err != nil { wizDepoGo(w, r, "conn", "сервер отвечает, но база "+s.DepoDB()+" недоступна этим логином — "+err.Error(), false) return } wizDepoGo(w, r, "tables", "подключение к "+s.Server+", база "+s.DepoDB()+" — работает", true) } // wizardDepoTables — POST /admin/setup/wizard-depo/tables: создать таблицы (bj) или проверить созданные // администратором по скрипту. func (h *setupHandlers) wizardDepoTables(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost || !requireDepo(w, r) { return } s := h.rc.Snapshot().Fancy mode := r.FormValue("depo_tables_mode") if mode != "script" { mode = "auto" } if s.DepoTablesMode != mode { s.DepoTablesMode = mode _ = h.rc.UpdateFancy(s) } ctx, cancel := context.WithTimeout(r.Context(), 2*time.Minute) defer cancel() if mode == "auto" && r.FormValue("action") != "check" { if _, err := depoTablesCreate(ctx, s, r.FormValue("admin_user"), r.FormValue("admin_password")); err != nil { wizDepoGo(w, r, "tables", "таблицы не созданы — "+err.Error()+". Если у логина bj нет прав, введите разово логин администратора SQL.", false) return } } msg, ok := depoTablesCheck(ctx, s) h.saveDepoTablesCheck(msg, ok) if !ok { wizDepoGo(w, r, "tables", msg, false) return } if !s.IsPostgres() { _ = depoWriteHandbook(h.rc) } wizDepoGo(w, r, "job", "таблицы обмена на месте: "+msg, true) } // wizardDepoJob — POST /admin/setup/wizard-depo/job: выбрать, кто запускает обработку, сделать нужное // (для «джобу создаёт bj» — создать) и проверить служебным событием. func (h *setupHandlers) wizardDepoJob(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost || !requireDepo(w, r) { return } s := h.rc.Snapshot().Fancy mode := r.FormValue("depo_job_mode") if mode != "bj" && mode != "sql-auto" && mode != "sql-manual" { mode = "sql-auto" } if s.DepoJobMode != mode { s.DepoJobCheck, s.DepoJobCheckOK = "", false } s.DepoJobMode, s.DepoJobRun = mode, mode == "bj" if err := h.rc.UpdateFancy(s); err != nil { wizDepoGo(w, r, "job", "не сохранилось: "+err.Error(), false) return } ctx, cancel := context.WithTimeout(r.Context(), 90*time.Second) defer cancel() if mode == "sql-auto" && r.FormValue("action") != "check" { if err := depoJobCreateAgent(ctx, h.rc, r.FormValue("admin_user"), r.FormValue("admin_password")); err != nil && !strings.Contains(err.Error(), "уже существует") { wizDepoGo(w, r, "job", "джоба не создана — "+err.Error(), false) return } } msg, ok := depoJobCheck(ctx, h.rc) s = h.rc.Snapshot().Fancy s.DepoJobCheck, s.DepoJobCheckOK, s.DepoJobCheckAt = msg, ok, time.Now() _ = h.rc.UpdateFancy(s) if !ok { wizDepoGo(w, r, "job", "обработка пока не работает — "+msg, false) return } wizDepoGo(w, r, "done", "обработка работает: "+msg, true) } // wizardDepoRecheck — POST /admin/setup/wizard-depo/recheck: перепроверить всё на экране «Готово». func (h *setupHandlers) wizardDepoRecheck(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost || !requireDepo(w, r) { return } s := h.rc.Snapshot().Fancy ctx, cancel := context.WithTimeout(r.Context(), 90*time.Second) defer cancel() if _, err := fancyPing(ctx, s, s.DepoDB()); err != nil { wizDepoGo(w, r, "conn", "подключение не работает — "+err.Error(), false) return } msg, ok := depoTablesCheck(ctx, s) h.saveDepoTablesCheck(msg, ok) if !ok { wizDepoGo(w, r, "tables", msg, false) return } jmsg, jok := depoJobCheck(ctx, h.rc) s = h.rc.Snapshot().Fancy s.DepoJobCheck, s.DepoJobCheckOK, s.DepoJobCheckAt = jmsg, jok, time.Now() _ = h.rc.UpdateFancy(s) if !jok { wizDepoGo(w, r, "job", jmsg, false) return } wizDepoGo(w, r, "done", "всё перепроверено", true) }