Мастер: пояснение к уже выполненным шагам, Валидата определяется сама без пути PKCS#11

Шаг «База bj» показывает, что базу создал установщик; шаг DEPO — почему пропущен.
Поле libvdpkcs11.so убрано (в Валидате 6.0 такого модуля нет, работа через bj-crypto).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-09-24 17:26:41 +03:00
parent 9ee2641431
commit 27bf8f6414
3 changed files with 91 additions and 36 deletions
+65 -7
View File
@@ -163,15 +163,19 @@ func (h *setupHandlers) renderNews(w http.ResponseWriter, r *http.Request) {
// WizardData — данные для шаблона /admin/wizard.
type WizardData struct {
page
Step int
Settings Settings
Suggest *DepoRequisites // предложение реквизитов из DEPO (после «Определить из DEPO»)
Step int
Settings Settings
Suggest *DepoRequisites // предложение реквизитов из DEPO (после «Определить из DEPO»)
Lic LicenseStatus
DepoLicensed bool
DepoDB string
Certs []cryptocli.Certificate
Flash string
Done struct {
ValidataVer string // версия установленной «Валидаты Клиент L» (пусто — не установлена)
CryptoSvc string // состояние службы bj-crypto (systemctl is-active)
PGSummary string // куда подключена база bj, без пароля
AutoDone []string // шаги до текущего, уже выполненные без участия пользователя, — с пояснением
Certs []cryptocli.Certificate
Flash string
Done struct {
License bool
Depo bool
Postgres bool
@@ -204,7 +208,17 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
d.DepoDB = s.Fancy.DepoDB()
d.Done.Depo = strings.TrimSpace(s.Fancy.Server) != "" || !d.DepoLicensed
d.Done.Postgres = s.Postgres.DSN != ""
d.Done.Crypto = s.Crypto.Provider != "" && s.Crypto.Provider != "stub" && s.Crypto.ModulePath != ""
{
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
d.ValidataVer, _, _ = validataVersion(ctx)
out, _ := exec.CommandContext(ctx, "systemctl", "is-active", "bj-crypto.service").Output()
cancel()
d.CryptoSvc = strings.TrimSpace(string(out))
}
d.PGSummary = dsnSummary(s.Postgres.DSN)
// Валидата ставится с образа/установщиком: если она на месте, шаг выполнен без ввода параметров
// (bj работает с ней через свой криптосервис, путь к модулю не нужен).
d.Done.Crypto = d.ValidataVer != "" || (s.Crypto.Provider != "" && s.Crypto.Provider != "stub" && s.Crypto.ModulePath != "")
d.Done.Certs = len(d.Certs) > 0
d.Done.NSD = s.NSD.IGWBaseURL != "" && s.NSD.Profile != ""
d.Done.TestRun = s.LastTest != nil || (!d.DevMode && d.Done.NSD) // вне режима разработки тестовой заявки нет
@@ -235,9 +249,53 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
}
}
d.Step = step
d.AutoDone = wizardAutoDone(&d)
render(w, h.tpl.a.wizard, d)
}
// wizardAutoDone — пояснения к шагам до текущего, которые уже выполнены: мастер переходит к первому
// незавершённому шагу сам, и без пояснения непонятно, почему предыдущие отмечены галочкой.
func wizardAutoDone(d *WizardData) []string {
var out []string
if d.Step > 1 && d.Done.License {
out = append(out, "1. Лицензия — активирована: "+d.Lic.Tenant+".")
}
if d.Step > 2 && d.Done.Postgres {
t := "2. База bj — готова"
if d.PGSummary != "" {
t += " (" + d.PGSummary + ")"
}
out = append(out, t+": её создал установщик, настраивать ничего не нужно.")
}
if d.Step > 3 && d.Done.Depo {
if !d.DepoLicensed {
out = append(out, "3. Учёт DEPO — не нужен: модуль обмена с DEPO и QUIK не входит в лицензию. Когда модуль добавят, шаг станет доступен.")
} else {
out = append(out, "3. Учёт DEPO — подключение уже сохранено ("+d.Settings.Fancy.Server+").")
}
}
if d.Step > 4 && d.Done.Crypto && d.ValidataVer != "" {
out = append(out, "4. Валидата — установлена вместе с bj (версия "+d.ValidataVer+").")
}
return out
}
// dsnSummary — «host:port, база name» из строки подключения PostgreSQL, без логина и пароля.
func dsnSummary(dsn string) string {
u, err := url.Parse(strings.TrimSpace(dsn))
if err != nil || u.Host == "" {
return ""
}
host := u.Host
if h := u.Hostname(); h == "127.0.0.1" || h == "localhost" || h == "::1" {
host = "PostgreSQL на этом сервере"
}
if db := strings.TrimPrefix(u.Path, "/"); db != "" {
return host + ", база " + db
}
return host
}
// runCmd выполняет команду и возвращает stdout+stderr строкой.
func runCmd(ctx context.Context, name string, args ...string) (string, error) {
cmd := exec.CommandContext(ctx, name, args...)