Files
Bridge-and-Join-s/internal/lkgateway/depodiscover.go
T
zuevav 8905ebc6fb Первичная настройка: ключ спрашивается один раз, затем обновления, модули и «Время и сеть»; DEPO одним шагом
- Первая страница — только администратор (и восстановление из копии); ключ продукта — после создания
  администратора, на шаге «Лицензия». Консоль первой загрузки ключ больше не спрашивает (для образа с
  комплектом bj).
- «Подготовка модулей» начинает с проверки обновлений: есть — ставит (bj перезапускается, страница ждёт и
  продолжает), нет — дальше; выпуск, который уже ставили, по кругу не ставится. Затем модули лицензии и
  переход на «Время и сеть» (шаг 12) — часовой пояс клиент выбирает сам, шаг больше не проскакивает.
- Учёт DEPO одним шагом: bj сам находит базу Fancy DEPO на сервере (по таблицам OD_FACES/OD_RESTS), имя
  базы не спрашивается. Один скрипт создаёт логин bj, таблицы обмена и права; по выбору — задание
  обработки в SQL Agent или обработка на сервере bj. Выполнить сразу (логин администратора СУБД не
  сохраняется), скачать скрипт для администратора или подключиться готовым логином.
- Восстановление из копии — только на первой странице, в мастере его больше нет.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
2026-10-06 11:42:10 +03:00

99 lines
3.5 KiB
Go

package lkgateway
// Поиск базы DEPO на сервере (05.10.2026). Клиент не знает и не должен знать, как называется база учёта у
// него на сервере: на шаге «Подключение» он вводит только адрес, логин и пароль, а bj сам находит базы с
// учётными таблицами Fancy DEPO (лица OD_FACES и остатки OD_RESTS), к которым у этого логина есть доступ.
// Одна база — выбирается сразу, несколько — мастер предлагает выбрать, ни одной — понятная ошибка.
import (
"context"
"fmt"
"strings"
"time"
)
// depoMarkerTables — по каким таблицам база опознаётся как DEPO (Fancy).
var depoMarkerTables = []string{"OD_FACES", "OD_RESTS"}
// depoDiscoverMax — сколько баз сервера просматривать (на сервере могут быть десятки баз).
const depoDiscoverMax = 60
// depoDiscover — базы DEPO на сервере, доступные этому логину.
func depoDiscover(ctx context.Context, s FancyMSSQLSettings) ([]string, error) {
cctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
if s.IsPostgres() {
return depoDiscoverPG(cctx, s)
}
conn, err := fancyOpen(s, "")
if err != nil {
return nil, err
}
defer conn.Close()
rows, err := conn.QueryContext(cctx, `SELECT name FROM sys.databases
WHERE state = 0 AND database_id > 4 AND HAS_DBACCESS(name) = 1 ORDER BY name`)
if err != nil {
return nil, fmt.Errorf("список баз сервера: %w", err)
}
var names []string
for rows.Next() {
var n string
if rows.Scan(&n) == nil && validDBName(n) && len(names) < depoDiscoverMax {
names = append(names, n)
}
}
rows.Close()
var found []string
for _, n := range names {
// имя проверено validDBName — подставлять в [ ] безопасно
q := "SELECT CASE WHEN " + strings.Join(func() []string {
var c []string
for _, t := range depoMarkerTables {
c = append(c, "OBJECT_ID(N'["+n+"].dbo."+t+"') IS NOT NULL")
}
return c
}(), " AND ") + " THEN 1 ELSE 0 END"
var ok int
if conn.QueryRowContext(cctx, q).Scan(&ok) == nil && ok == 1 {
found = append(found, n)
}
}
return found, nil
}
func depoDiscoverPG(ctx context.Context, s FancyMSSQLSettings) ([]string, error) {
conn, err := fancyOpen(s, "")
if err != nil {
return nil, err
}
defer conn.Close()
rows, err := conn.QueryContext(ctx, `SELECT datname FROM pg_database
WHERE datallowconn AND NOT datistemplate AND has_database_privilege(datname, 'CONNECT') ORDER BY datname`)
if err != nil {
return nil, fmt.Errorf("список баз сервера: %w", err)
}
var names []string
for rows.Next() {
var n string
if rows.Scan(&n) == nil && validDBName(n) && n != "postgres" && len(names) < depoDiscoverMax {
names = append(names, n)
}
}
rows.Close()
var found []string
for _, n := range names {
db, err := fancyOpen(s, n)
if err != nil {
continue
}
var cnt int
err = db.QueryRowContext(ctx, `SELECT count(DISTINCT lower(table_name)) FROM information_schema.tables
WHERE lower(table_name) = ANY($1::text[])`, "{"+strings.ToLower(strings.Join(depoMarkerTables, ","))+"}").Scan(&cnt)
db.Close()
if err == nil && cnt == len(depoMarkerTables) {
found = append(found, n)
}
}
return found, nil
}