feat(mindspace): enforce PostgreSQL user data delivery

This commit is contained in:
john
2026-07-13 15:29:29 +08:00
parent b33c943b69
commit a6620fb719
57 changed files with 2779 additions and 164 deletions
+19 -19
View File
@@ -171,13 +171,13 @@ export function createPageDataPublicService(deps = {}) {
});
}
function resolveEffectiveDataset(ownerUserId, policy, datasetName, rolePermissions = null) {
async function resolveEffectiveDataset(ownerUserId, policy, datasetName, rolePermissions = null) {
const policyDataset = policy.datasets?.[datasetName];
if (!policyDataset) {
throw Object.assign(new Error('dataset 未授权'), { code: 'action_not_allowed' });
}
const ownerService = createOwnerService(ownerUserId);
const registryDataset = ownerService.getDataset(datasetName);
const registryDataset = await ownerService.getDataset(datasetName);
if (!registryDataset) {
throw Object.assign(new Error('dataset 不存在'), { code: 'dataset_not_found' });
}
@@ -190,9 +190,9 @@ export function createPageDataPublicService(deps = {}) {
return { ownerService, effective, policyDataset };
}
function resolveRowScope(ownerService, effective, policyDataset, visitorContext) {
async function resolveRowScope(ownerService, effective, policyDataset, visitorContext) {
if (!policyDataset?.rowPolicy || !visitorContext) return null;
const tableColumns = ownerService.listTableColumns(effective.table);
const tableColumns = await ownerService.listTableColumns(effective.table);
return resolveRowAccessScope(policyDataset.rowPolicy, {
visitorRole: visitorContext.visitorRole,
visitorUserId: visitorContext.visitorUserId,
@@ -303,13 +303,13 @@ export function createPageDataPublicService(deps = {}) {
const policy = await loadPolicy(publication);
const access = resolveAccessContext({ publication, policy, req, action: 'read', datasetName });
enforceRateLimit(req, publication, 'read');
const { ownerService, effective, policyDataset } = resolveEffectiveDataset(
const { ownerService, effective, policyDataset } = await resolveEffectiveDataset(
publication.user_id,
policy,
datasetName,
access.rolePermissions ?? null,
);
const rowScope = resolveRowScope(
const rowScope = await resolveRowScope(
ownerService,
effective,
policyDataset,
@@ -330,7 +330,7 @@ export function createPageDataPublicService(deps = {}) {
const publication = await queryPublication(pageId);
const policy = await loadPolicy(publication);
const access = resolveAccessContext({ publication, policy, req, action: 'read', datasetName });
const { ownerService, effective } = resolveEffectiveDataset(
const { ownerService, effective } = await resolveEffectiveDataset(
publication.user_id,
policy,
datasetName,
@@ -345,13 +345,13 @@ export function createPageDataPublicService(deps = {}) {
const publication = await queryPublication(pageId);
const policy = await loadPolicy(publication);
const access = resolveAccessContext({ publication, policy, req, action: 'read', datasetName });
const { ownerService, effective, policyDataset } = resolveEffectiveDataset(
const { ownerService, effective, policyDataset } = await resolveEffectiveDataset(
publication.user_id,
policy,
datasetName,
access.rolePermissions ?? null,
);
const rowScope = resolveRowScope(
const rowScope = await resolveRowScope(
ownerService,
effective,
policyDataset,
@@ -415,13 +415,13 @@ export function createPageDataPublicService(deps = {}) {
}
const payload = stripPageDataMetaFields(payloadInput);
enforceRateLimit(req, publication, 'insert');
const { ownerService, effective, policyDataset } = resolveEffectiveDataset(
const { ownerService, effective, policyDataset } = await resolveEffectiveDataset(
publication.user_id,
policy,
datasetName,
access.rolePermissions ?? null,
);
const rowScope = resolveRowScope(
const rowScope = await resolveRowScope(
ownerService,
effective,
policyDataset,
@@ -465,13 +465,13 @@ export function createPageDataPublicService(deps = {}) {
datasetName,
});
enforceRateLimit(req, publication, 'update');
const { ownerService, effective, policyDataset } = resolveEffectiveDataset(
const { ownerService, effective, policyDataset } = await resolveEffectiveDataset(
publication.user_id,
policy,
datasetName,
access.rolePermissions ?? null,
);
const rowScope = resolveRowScope(
const rowScope = await resolveRowScope(
ownerService,
effective,
policyDataset,
@@ -513,13 +513,13 @@ export function createPageDataPublicService(deps = {}) {
datasetName,
});
enforceRateLimit(req, publication, 'soft_delete');
const { ownerService, effective, policyDataset } = resolveEffectiveDataset(
const { ownerService, effective, policyDataset } = await resolveEffectiveDataset(
publication.user_id,
policy,
datasetName,
access.rolePermissions ?? null,
);
const rowScope = resolveRowScope(
const rowScope = await resolveRowScope(
ownerService,
effective,
policyDataset,
@@ -598,7 +598,7 @@ export function createPageDataPublicService(deps = {}) {
throw Object.assign(new Error('缺少 dataset 名称'), { code: 'invalid_request', status: 400 });
}
const ownerService = createOwnerService(user.id);
const registryDataset = ownerService.getDataset(normalizedDatasetName);
const registryDataset = await ownerService.getDataset(normalizedDatasetName);
if (!registryDataset) {
throw Object.assign(new Error('dataset 未注册'), { code: 'dataset_not_found', status: 404 });
}
@@ -639,8 +639,8 @@ export function createPageDataPublicService(deps = {}) {
for (const [name, config] of Object.entries(policy.datasets ?? {})) {
let stats = null;
try {
if (ownerService.getDataset(name)) {
stats = ownerService.getDatasetStats(name);
if (await ownerService.getDataset(name)) {
stats = await ownerService.getDatasetStats(name);
}
} catch {
stats = null;
@@ -660,7 +660,7 @@ export function createPageDataPublicService(deps = {}) {
const recentSubmissions = logs.filter((entry) => entry.action === 'insert').slice(0, 10);
const activeSessions = sessionStore.listByPageId(pageId);
const index = await getPageDataPolicyIndex(getPool(), pageId);
const registeredDatasets = ownerService.listDatasets().map((dataset) => dataset.name);
const registeredDatasets = (await ownerService.listDatasets()).map((dataset) => dataset.name);
const configuredNames = new Set(Object.keys(policy.datasets ?? {}));
const unconfiguredDatasets = registeredDatasets.filter((name) => !configuredNames.has(name));
return {