DEPO: логину bj — роль db_datawriter (как на тесте); при обновлении и в первичной установке
Процедуры Фонтвьель, вызванные bj (FTV_M2M_JOB → EVENTS → UPDATE_HANDBOOK, CREATE, OPERATION), пишут в таблицы Fancy правами логина bj. На 9 у bj_user был только db_datareader — «Запрещено разрешение INSERT на объект OD_OBJECTS» (событие HANDBOOK, 22.10.2026); упали бы и поручения M2M. На тесте — db_datareader + db_datawriter. Роль выдаётся в наборе «Применить скрипты» (права администратора БД; новый отпечаток — плашка на установках), в скачиваемом скрипте процедур, в скрипте логина и при подготовке трансферных таблиц (первичная установка). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -101,6 +101,7 @@ func depoProcsHash(f FancyMSSQLSettings) string {
|
|||||||
for _, fx := range depoSchemaFixes {
|
for _, fx := range depoSchemaFixes {
|
||||||
h.Write([]byte(fx.Name + "\n" + fx.SQL + "\n"))
|
h.Write([]byte(fx.Name + "\n" + fx.SQL + "\n"))
|
||||||
}
|
}
|
||||||
|
h.Write([]byte("grant db_datawriter\n")) // 22.10.2026: роль записи логину bj — новый отпечаток, плашка на установках
|
||||||
for _, p := range depoProcInstallOrder {
|
for _, p := range depoProcInstallOrder {
|
||||||
h.Write([]byte(p.Name + "\n" + strings.TrimSpace(depoProcEffective(f, p.Name)) + "\n"))
|
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"))
|
fmt.Fprintf(&b, "/* ===== %s ===== */\n%s\nGO\n\n", p.Name, strings.TrimRight(body, "\n"))
|
||||||
}
|
}
|
||||||
if depoLoginRe.MatchString(login) {
|
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")
|
b.WriteString("/* Права логину bj на все процедуры: без прав OBJECT_ID не видит их и проверка пишет «нет процедур» */\n")
|
||||||
for _, p := range depoProcInstallOrder {
|
for _, p := range depoProcInstallOrder {
|
||||||
fmt.Fprintf(&b, "GRANT EXECUTE ON dbo.%s TO %s;\n", p.Name, quoteIdent(login))
|
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) {
|
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, и проверка пишет «нет процедур».
|
// Право на ВСЕ процедуры: без него OBJECT_ID под bj_user = NULL, и проверка пишет «нет процедур».
|
||||||
for _, p := range depoProcInstallOrder {
|
for _, p := range depoProcInstallOrder {
|
||||||
if _, err := db.ExecContext(ctx, "GRANT EXECUTE ON dbo."+p.Name+" TO "+quoteIdent(grantLogin)); err != nil {
|
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 {
|
if err := depoProcsInstallInto(ctx, adm, f, f.DepoDB(), login); err != nil {
|
||||||
return "", err
|
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)
|
log.Printf("depo-procs: %s", msg)
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
fmt.Fprintf(&b, `-- Bridge&Join: логин для bj в базе DEPO. Microsoft SQL Server.
|
||||||
-- Выполнить в SSMS или sqlcmd под логином с правами sysadmin (или securityadmin + db_owner в базе %[1]s).
|
-- Выполнить в 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];
|
USE [master];
|
||||||
GO
|
GO
|
||||||
@@ -75,6 +76,9 @@ GO
|
|||||||
|
|
||||||
IF IS_ROLEMEMBER(N'db_datareader', N'%[2]s') = 0 ALTER ROLE db_datareader ADD MEMBER [%[2]s];
|
IF IS_ROLEMEMBER(N'db_datareader', N'%[2]s') = 0 ALTER ROLE db_datareader ADD MEMBER [%[2]s];
|
||||||
GO
|
GO
|
||||||
|
|
||||||
|
IF IS_ROLEMEMBER(N'db_datawriter', N'%[2]s') = 0 ALTER ROLE db_datawriter ADD MEMBER [%[2]s];
|
||||||
|
GO
|
||||||
`, db, login, pw)
|
`, db, login, pw)
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
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 (лица, счета, остатки, опции) — для сверки заявок
|
// чтение учётных таблиц DEPO (лица, счета, остатки, опции) — для сверки заявок
|
||||||
fmt.Sprintf("IF IS_ROLEMEMBER(N'db_datareader', N'%[1]s') = 0 ALTER ROLE db_datareader ADD MEMBER [%[1]s]", user),
|
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() {
|
for _, n := range depoTableNames() {
|
||||||
out = append(out, fmt.Sprintf("GRANT SELECT, INSERT, UPDATE, DELETE ON dbo.%s TO [%s]", n, user))
|
out = append(out, fmt.Sprintf("GRANT SELECT, INSERT, UPDATE, DELETE ON dbo.%s TO [%s]", n, user))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{define "depoProcsBanner"}}{{if and (can "settings") depoProcsPending}}<div class="card" id="depo-procs-pending" style="border-color:var(--warn);background:var(--warn-weak)">
|
{{define "depoProcsBanner"}}{{if and (can "settings") depoProcsPending}}<div class="card" id="depo-procs-pending" style="border-color:var(--warn);background:var(--warn-weak)">
|
||||||
<h2 style="margin:0 0 6px">Обновление bj требует применить скрипты в базе DEPO</h2>
|
<h2 style="margin:0 0 6px">Обновление bj требует применить скрипты в базе DEPO</h2>
|
||||||
<p style="margin:0 0 8px">В этой версии bj обновлены процедуры обработки M2M в DEPO ({{depoProcOrder}}) и структура трансферных таблиц (FTV_M2M_EVENTS.GUID — NULL для событий справочника). Для их установки нужны <b>повышенные права на базу данных</b>: введите логин и пароль администратора SQL (sysadmin, обычно sa). Они используются один раз и не сохраняются.</p>
|
<p style="margin:0 0 8px">В этой версии bj обновлены процедуры обработки M2M в DEPO ({{depoProcOrder}}) и структура трансферных таблиц (FTV_M2M_EVENTS.GUID — NULL для событий справочника); логину bj — роль db_datawriter (процедуры обработки создают документы и юрлица Fancy его правами). Для их установки нужны <b>повышенные права на базу данных</b>: введите логин и пароль администратора SQL (sysadmin, обычно sa). Они используются один раз и не сохраняются.</p>
|
||||||
<form method="post" action="/admin/setup/fancy/depo-procs/install" style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end" onsubmit="return confirm('Применить обновлённые процедуры в базе DEPO? CREATE OR ALTER — данные не меняются.')">
|
<form method="post" action="/admin/setup/fancy/depo-procs/install" style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end" onsubmit="return confirm('Применить обновлённые процедуры в базе DEPO? CREATE OR ALTER — данные не меняются.')">
|
||||||
<input type="hidden" name="section" value="sec-fancy-depo-procs">
|
<input type="hidden" name="section" value="sec-fancy-depo-procs">
|
||||||
<label style="display:flex;flex-direction:column;gap:3px">Логин администратора SQL<input type="text" name="admin_user" autocomplete="off" placeholder="sa" required></label>
|
<label style="display:flex;flex-direction:column;gap:3px">Логин администратора SQL<input type="text" name="admin_user" autocomplete="off" placeholder="sa" required></label>
|
||||||
|
|||||||
Reference in New Issue
Block a user