import crypto from 'node:crypto'; export function buildPageDataPolicyScopeHash(policy) { const payload = { accessMode: policy?.accessMode ?? null, datasets: Object.keys(policy?.datasets ?? {}).sort(), }; return crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex').slice(0, 16); } export async function upsertPageDataPolicyIndex(pool, policy) { if (!pool || !policy?.pageId || !policy?.ownerUserId) return null; const datasetCount = Object.keys(policy.datasets ?? {}).length; const now = Date.now(); await pool.query( `INSERT INTO h5_page_data_policy_index (page_id, owner_user_id, access_mode, dataset_count, scope_hash, updated_at) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE owner_user_id = VALUES(owner_user_id), access_mode = VALUES(access_mode), dataset_count = VALUES(dataset_count), scope_hash = VALUES(scope_hash), updated_at = VALUES(updated_at)`, [ policy.pageId, policy.ownerUserId, policy.accessMode, datasetCount, buildPageDataPolicyScopeHash(policy), now, ], ); return { pageId: policy.pageId, ownerUserId: policy.ownerUserId, accessMode: policy.accessMode, datasetCount, scopeHash: buildPageDataPolicyScopeHash(policy), updatedAt: now, }; } export async function getPageDataPolicyIndex(pool, pageId) { if (!pool) return null; const [rows] = await pool.query( `SELECT page_id, owner_user_id, access_mode, dataset_count, scope_hash, updated_at FROM h5_page_data_policy_index WHERE page_id = ? LIMIT 1`, [pageId], ); const row = rows[0]; if (!row) return null; return { pageId: row.page_id, ownerUserId: row.owner_user_id, accessMode: row.access_mode, datasetCount: Number(row.dataset_count ?? 0), scopeHash: row.scope_hash, updatedAt: Number(row.updated_at ?? 0), }; } export async function listPageDataPolicyIndexByOwner(pool, ownerUserId, { limit = 50 } = {}) { if (!pool) return []; const safeLimit = Math.min(Math.max(1, Number(limit ?? 50)), 200); const [rows] = await pool.query( `SELECT page_id, owner_user_id, access_mode, dataset_count, scope_hash, updated_at FROM h5_page_data_policy_index WHERE owner_user_id = ? ORDER BY updated_at DESC LIMIT ?`, [ownerUserId, safeLimit], ); return rows.map((row) => ({ pageId: row.page_id, ownerUserId: row.owner_user_id, accessMode: row.access_mode, datasetCount: Number(row.dataset_count ?? 0), scopeHash: row.scope_hash, updatedAt: Number(row.updated_at ?? 0), })); } export async function deletePageDataPolicyIndex(pool, pageId) { if (!pool || !pageId) return false; const [result] = await pool.query(`DELETE FROM h5_page_data_policy_index WHERE page_id = ?`, [pageId]); return Number(result?.affectedRows ?? 0) > 0; }