diff --git a/internal/lkgateway/depo_procs.go b/internal/lkgateway/depo_procs.go index e2a613a..aab1cc6 100644 --- a/internal/lkgateway/depo_procs.go +++ b/internal/lkgateway/depo_procs.go @@ -101,6 +101,7 @@ func depoProcsHash(f FancyMSSQLSettings) string { for _, fx := range depoSchemaFixes { h.Write([]byte(fx.Name + "\n" + fx.SQL + "\n")) } + h.Write([]byte("grant db_datawriter\n")) // 22.10.2026: роль записи логину bj — новый отпечаток, плашка на установках for _, p := range depoProcInstallOrder { h.Write([]byte(p.Name + "\n" + strings.TrimSpace(depoProcEffective(f, p.Name)) + "\n")) } @@ -147,6 +148,8 @@ func depoProcsScriptFor(f FancyMSSQLSettings, db, login string) string { fmt.Fprintf(&b, "/* ===== %s ===== */\n%s\nGO\n\n", p.Name, strings.TrimRight(body, "\n")) } if depoLoginRe.MatchString(login) { + b.WriteString("/* Запись в таблицы Fancy: процедуры обработки M2M работают правами логина bj (без неё — «Запрещено разрешение INSERT на объект OD_OBJECTS») */\n") + fmt.Fprintf(&b, "IF IS_ROLEMEMBER(N'db_datawriter', N'%[1]s') = 0 ALTER ROLE db_datawriter ADD MEMBER %[2]s;\nGO\n", login, quoteIdent(login)) b.WriteString("/* Права логину bj на все процедуры: без прав OBJECT_ID не видит их и проверка пишет «нет процедур» */\n") for _, p := range depoProcInstallOrder { fmt.Fprintf(&b, "GRANT EXECUTE ON dbo.%s TO %s;\n", p.Name, quoteIdent(login)) @@ -181,6 +184,10 @@ func depoProcsInstallInto(ctx context.Context, adm, f FancyMSSQLSettings, dbName } } if depoLoginRe.MatchString(grantLogin) { + // Запись в таблицы Fancy: процедуры Фонтвьель, вызванные bj, работают правами логина bj. + if _, err := db.ExecContext(ctx, "IF DATABASE_PRINCIPAL_ID(N'"+grantLogin+"') IS NOT NULL AND IS_ROLEMEMBER(N'db_datawriter', N'"+grantLogin+"') = 0 ALTER ROLE db_datawriter ADD MEMBER "+quoteIdent(grantLogin)); err != nil { + return fmt.Errorf("роль db_datawriter логину %s: %s", grantLogin, quikErrorDetail(err)) + } // Право на ВСЕ процедуры: без него OBJECT_ID под bj_user = NULL, и проверка пишет «нет процедур». for _, p := range depoProcInstallOrder { if _, err := db.ExecContext(ctx, "GRANT EXECUTE ON dbo."+p.Name+" TO "+quoteIdent(grantLogin)); err != nil { @@ -294,7 +301,7 @@ func depoProcsInstall(ctx context.Context, f FancyMSSQLSettings, adminUser, admi if err := depoProcsInstallInto(ctx, adm, f, f.DepoDB(), login); err != nil { return "", err } - msg := fmt.Sprintf("структура таблиц проверена; установлено процедур: %d (%s); право EXECUTE логину %s выдано", len(depoProcInstallOrder), depoProcOrderText(", "), login) + msg := fmt.Sprintf("структура таблиц проверена; установлено процедур: %d (%s); логину %s — EXECUTE и роль db_datawriter", len(depoProcInstallOrder), depoProcOrderText(", "), login) log.Printf("depo-procs: %s", msg) return msg, nil } diff --git a/internal/lkgateway/depologin.go b/internal/lkgateway/depologin.go index a9c766c..53856fa 100644 --- a/internal/lkgateway/depologin.go +++ b/internal/lkgateway/depologin.go @@ -51,8 +51,9 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "%[2]s"; fmt.Fprintf(&b, `-- Bridge&Join: логин для bj в базе DEPO. Microsoft SQL Server. -- Выполнить в SSMS или sqlcmd под логином с правами sysadmin (или securityadmin + db_owner в базе %[1]s). -- Пароль — из поля мастера; если там пусто, замените ЗАМЕНИТЕ_НА_ПАРОЛЬ на свой. Скрипт с паролем не храните. --- Права: только чтение учётных таблиц DEPO (db_datareader). Запись — только в таблицы обмена FTV_M2M*, --- её выдаёт скрипт таблиц на следующем шаге мастера. Скрипт можно запускать повторно. +-- Права: чтение учётных таблиц DEPO (db_datareader) и запись (db_datawriter) — процедуры обработки M2M +-- (FTV_M2M_JOB и др.), которые вызывает bj, создают документы, операции и юрлица Fancy правами этого логина. +-- Таблицы обмена FTV_M2M* выдаёт скрипт таблиц на следующем шаге мастера. Скрипт можно запускать повторно. USE [master]; GO @@ -75,6 +76,9 @@ GO IF IS_ROLEMEMBER(N'db_datareader', N'%[2]s') = 0 ALTER ROLE db_datareader ADD MEMBER [%[2]s]; GO + +IF IS_ROLEMEMBER(N'db_datawriter', N'%[2]s') = 0 ALTER ROLE db_datawriter ADD MEMBER [%[2]s]; +GO `, db, login, pw) return b.String() } diff --git a/internal/lkgateway/depotables.go b/internal/lkgateway/depotables.go index b64e6eb..10b0c58 100644 --- a/internal/lkgateway/depotables.go +++ b/internal/lkgateway/depotables.go @@ -237,6 +237,8 @@ func depoTablesGrantSQL(pg bool, user string) []string { fmt.Sprintf("IF EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N'%[1]s' AND sid <> SUSER_SID(N'%[1]s')) ALTER USER [%[1]s] WITH LOGIN = [%[1]s]", user), // чтение учётных таблиц DEPO (лица, счета, остатки, опции) — для сверки заявок fmt.Sprintf("IF IS_ROLEMEMBER(N'db_datareader', N'%[1]s') = 0 ALTER ROLE db_datareader ADD MEMBER [%[1]s]", user), + // запись в таблицы Fancy — процедуры обработки M2M (FTV_M2M_JOB…) работают правами вызывающего (bj) + fmt.Sprintf("IF IS_ROLEMEMBER(N'db_datawriter', N'%[1]s') = 0 ALTER ROLE db_datawriter ADD MEMBER [%[1]s]", user), } for _, n := range depoTableNames() { out = append(out, fmt.Sprintf("GRANT SELECT, INSERT, UPDATE, DELETE ON dbo.%s TO [%s]", n, user)) diff --git a/internal/lkgateway/web/templates/layout.html b/internal/lkgateway/web/templates/layout.html index e160998..e792a33 100644 --- a/internal/lkgateway/web/templates/layout.html +++ b/internal/lkgateway/web/templates/layout.html @@ -1,6 +1,6 @@ {{define "depoProcsBanner"}}{{if and (can "settings") depoProcsPending}}
В этой версии bj обновлены процедуры обработки M2M в DEPO ({{depoProcOrder}}) и структура трансферных таблиц (FTV_M2M_EVENTS.GUID — NULL для событий справочника). Для их установки нужны повышенные права на базу данных: введите логин и пароль администратора SQL (sysadmin, обычно sa). Они используются один раз и не сохраняются.
+В этой версии bj обновлены процедуры обработки M2M в DEPO ({{depoProcOrder}}) и структура трансферных таблиц (FTV_M2M_EVENTS.GUID — NULL для событий справочника); логину bj — роль db_datawriter (процедуры обработки создают документы и юрлица Fancy его правами). Для их установки нужны повышенные права на базу данных: введите логин и пароль администратора SQL (sysadmin, обычно sa). Они используются один раз и не сохраняются.