Extend template sync script to generate frontend allow/deny lists so ProgramSettingsPage can hide can_edit=1 keys before API purge deploys. Co-authored-by: Cursor <cursoragent@cursor.com>
148 lines
5.0 KiB
JavaScript
148 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* منبع حقیقت: khaneghi_server/database/sql/deploy_settings_const.sql
|
|
* خروجی:
|
|
* - prisma/setting-templates-from-deploy.json (فقط can_edit=0 نهایی)
|
|
* - src/program-settings/deploy-setting-catalog-keys.ts
|
|
* - ../controlpanel_user/src/config/superAdminSettingKeys.ts
|
|
*/
|
|
import { readFileSync, writeFileSync } from 'fs';
|
|
import { dirname, join } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const root = join(__dirname, '..');
|
|
const sqlPath = join(
|
|
root,
|
|
'../khaneghi_server/database/sql/deploy_settings_const.sql',
|
|
);
|
|
|
|
const sql = readFileSync(sqlPath, 'utf8');
|
|
|
|
/** @type {Map<string, { key: string, value: string, title_fa: string, can_edit: number, is_active: number, description: string, type: string }>} */
|
|
const rows = new Map();
|
|
|
|
function unquote(s) {
|
|
return String(s ?? '')
|
|
.trim()
|
|
.replace(/^'/, '')
|
|
.replace(/'$/, '')
|
|
.replace(/\\'/g, "'")
|
|
.replace(/\\n/g, '\n');
|
|
}
|
|
|
|
// INSERT … SELECT 'key', 'value', …
|
|
for (const m of sql.matchAll(
|
|
/SELECT\s+'([^']+)',\s+'((?:\\'|[^'])*)',\s+'((?:\\'|[^'])*)',\s+(\d+),\s+(\d+)(?:,\s+(NULL|'(?:\\'|[^'])*'))(?:,\s+'((?:\\'|[^'])*)')?/g,
|
|
)) {
|
|
const key = m[1];
|
|
const value = unquote(`'${m[2]}'`);
|
|
const title_fa = unquote(`'${m[3]}'`);
|
|
const can_edit = Number(m[4]);
|
|
const is_active = Number(m[5]);
|
|
let description = '';
|
|
if (m[6] && m[6] !== 'NULL') description = unquote(m[6]);
|
|
const type = m[7] ? unquote(`'${m[7]}'`) : '';
|
|
rows.set(key, { key, value, title_fa, can_edit, is_active, description, type });
|
|
}
|
|
|
|
function applyCanEdit(block, value) {
|
|
const keys = [...block.matchAll(/'([^']+)'/g)].map((x) => x[1]);
|
|
for (const key of keys) {
|
|
const row = rows.get(key);
|
|
if (row) row.can_edit = value;
|
|
}
|
|
}
|
|
|
|
// UPDATE can_edit = 0/1 batches
|
|
for (const m of sql.matchAll(
|
|
/UPDATE\s+`settings`\s+SET\s+`can_edit`\s*=\s*(\d)(?:,\s*`[^`]+`\s*=[^W]+)?\s+WHERE\s+`key`\s+IN\s*\(([\s\S]*?)\)\s*;/g,
|
|
)) {
|
|
applyCanEdit(m[2], Number(m[1]));
|
|
}
|
|
|
|
for (const m of sql.matchAll(
|
|
/UPDATE\s+`settings`\s+SET\s+`can_edit`\s*=\s*(\d)\s+WHERE\s+`key`\s*=\s*'([^']+)'/g,
|
|
)) {
|
|
const row = rows.get(m[2]);
|
|
if (row) row.can_edit = Number(m[1]);
|
|
}
|
|
|
|
// zarin_* wildcard
|
|
if (/UPDATE\s+`settings`\s+SET\s+`can_edit`\s*=\s*0,\s*`is_active`\s*=\s*1\s+WHERE\s+`key`\s+LIKE\s+'zarin_%'/.test(sql)) {
|
|
for (const [key, row] of rows) {
|
|
if (key.startsWith('zarin_')) row.can_edit = 0;
|
|
}
|
|
}
|
|
|
|
// type-only UPDATE batches — enrich type when present
|
|
for (const m of sql.matchAll(
|
|
/UPDATE\s+`settings`\s+SET\s+`type`\s*=\s*'([^']+)'\s+WHERE\s+`key`\s+IN\s*\(([\s\S]*?)\)\s*;/g,
|
|
)) {
|
|
const type = m[1];
|
|
for (const key of [...m[2].matchAll(/'([^']+)'/g)].map((x) => x[1])) {
|
|
const row = rows.get(key);
|
|
if (row && type) row.type = type;
|
|
}
|
|
}
|
|
|
|
const systemRows = [...rows.values()]
|
|
.filter((r) => r.can_edit === 0)
|
|
.sort((a, b) => a.key.localeCompare(b.key));
|
|
|
|
const editableRows = [...rows.values()]
|
|
.filter((r) => r.can_edit === 1)
|
|
.sort((a, b) => a.key.localeCompare(b.key));
|
|
|
|
const jsonOut = systemRows.map((r) => ({
|
|
key: r.key,
|
|
value: r.value ?? '',
|
|
title_fa: r.title_fa ?? r.key,
|
|
can_edit: 0,
|
|
is_active: r.is_active ?? 1,
|
|
description: r.description ?? '',
|
|
type: r.type ?? '',
|
|
}));
|
|
|
|
const tsKeys = `/**
|
|
* کلیدهای can_edit=0 در deploy_settings_const.sql — فقط همینها در قالب سوپرادمین.
|
|
* تولید خودکار: node scripts/sync-superadmin-setting-template.mjs
|
|
*/
|
|
export const DEPLOY_SETTING_CATALOG_KEYS = new Set<string>([
|
|
${systemRows.map((r) => ` ${JSON.stringify(r.key)},`).join('\n')}
|
|
]);
|
|
|
|
/** کلیدهای can_edit=1 — نباید در قالب/جدول settings سوپرادمین باشند */
|
|
export const DEPLOY_SETTING_EDITABLE_KEYS = new Set<string>([
|
|
${editableRows.map((r) => ` ${JSON.stringify(r.key)},`).join('\n')}
|
|
]);
|
|
`;
|
|
|
|
writeFileSync(join(root, 'prisma/setting-templates-from-deploy.json'), `${JSON.stringify(jsonOut, null, 2)}\n`);
|
|
writeFileSync(join(root, 'src/program-settings/deploy-setting-catalog-keys.ts'), `${tsKeys}\n`);
|
|
|
|
const userTs = `/**
|
|
* کلیدهای تنظیمات سوپرادمین — همتراز deploy_settings_const.sql
|
|
* تولید خودکار: controlpanel_server/scripts/sync-superadmin-setting-template.mjs
|
|
*/
|
|
export const SUPERADMIN_SYSTEM_SETTING_KEYS = new Set<string>([
|
|
${systemRows.map((r) => ` ${JSON.stringify(r.key)},`).join('\n')}
|
|
]);
|
|
|
|
export const SUPERADMIN_EDITABLE_SETTING_KEYS = new Set<string>([
|
|
${editableRows.map((r) => ` ${JSON.stringify(r.key)},`).join('\n')}
|
|
]);
|
|
|
|
export function isSuperAdminSystemSettingKey(key?: string | null): boolean {
|
|
const k = String(key || '').trim();
|
|
if (!k) return false;
|
|
if (SUPERADMIN_EDITABLE_SETTING_KEYS.has(k)) return false;
|
|
return SUPERADMIN_SYSTEM_SETTING_KEYS.has(k);
|
|
}
|
|
`;
|
|
|
|
writeFileSync(join(root, '../controlpanel_user/src/config/superAdminSettingKeys.ts'), `${userTs}\n`);
|
|
|
|
console.log(`system keys (can_edit=0): ${systemRows.length}`);
|
|
console.log(`editable keys (can_edit=1): ${editableRows.length}`);
|