import { createUserDataSpaceService } from './user-data-space-service.mjs'; import { listPageDataLogs } from './page-data-log-store.mjs'; import { readPageAccessPolicy } from './page-data-policy-store.mjs'; function mapServiceError(error) { const code = error?.code; if (code === 'dataset_not_found') { return { status: 404, code: 'dataset_not_found', message: '数据集不存在' }; } if (code === 'action_not_allowed') { return { status: 403, code: 'action_not_allowed', message: error.message }; } if (code === 'columns_not_allowed') { return { status: 403, code: 'columns_not_allowed', message: error.message }; } if (code === 'invalid_row_id' || code === 'restore_unsupported') { return { status: 400, code: code ?? 'invalid_request', message: error.message }; } if (code === 'invalid_payload' || code === 'payload_too_large' || code === 'invalid_dataset_config') { return { status: 400, code: code ?? 'invalid_request', message: error.message }; } if (code === 'table_not_found') { return { status: 400, code: 'table_not_found', message: '数据集对应表不存在' }; } return { status: 400, code: 'page_data_failed', message: error instanceof Error ? error.message : '页面数据操作失败', }; } export function createPageDataService(deps = {}) { const getUserAuth = deps.getUserAuth ?? (() => null); const getPool = deps.getPool ?? (() => null); const resolveWorkspaceRoot = deps.resolveWorkspaceRoot ?? (async (user) => user?.workspaceRoot ?? null); async function createServiceForUser(user) { if (!user?.id) { throw Object.assign(new Error('未授权'), { code: 'unauthorized' }); } const workspaceRoot = await resolveWorkspaceRoot(user); if (!workspaceRoot) { throw Object.assign(new Error('用户工作区不存在'), { code: 'workspace_not_found' }); } const pool = getPool(); return { workspaceRoot, service: createUserDataSpaceService({ workspaceRoot, userId: user.id, query: pool ?? null, }), }; } async function listRows(user, datasetName, query = {}) { const { service } = await createServiceForUser(user); try { return await service.readDatasetRows(datasetName, { limit: query.limit, offset: query.offset, orderBy: query.orderBy ?? query.order_by, orderDir: query.orderDir ?? query.order_dir, includeDeleted: ['1', 'true', 'yes'].includes(String(query.include_deleted ?? '').toLowerCase()), }); } catch (error) { throw mapServiceError(error); } } async function getSchema(user, datasetName) { const { service } = await createServiceForUser(user); try { return await service.getDatasetSchema(datasetName); } catch (error) { throw mapServiceError(error); } } async function getStats(user, datasetName) { const { service } = await createServiceForUser(user); try { return await service.getDatasetStats(datasetName); } catch (error) { throw mapServiceError(error); } } async function insertRow(user, datasetName, payload) { const { service } = await createServiceForUser(user); try { return service.insertDatasetRow(datasetName, payload); } catch (error) { throw mapServiceError(error); } } async function updateRow(user, datasetName, rowId, payload) { const { service } = await createServiceForUser(user); try { return service.updateDatasetRow(datasetName, rowId, payload); } catch (error) { throw mapServiceError(error); } } async function softDeleteRow(user, datasetName, rowId) { const { service } = await createServiceForUser(user); try { return service.softDeleteDatasetRow(datasetName, rowId, { deletedBy: user.id }); } catch (error) { throw mapServiceError(error); } } async function restoreRow(user, datasetName, rowId) { const { service } = await createServiceForUser(user); try { return service.restoreSoftDeletedRow(datasetName, rowId); } catch (error) { throw mapServiceError(error); } } async function exportDataset(user, datasetName, query = {}) { const { service } = await createServiceForUser(user); try { return service.exportDatasetRows(datasetName, { format: query.format, includeDeleted: ['1', 'true', 'yes'].includes(String(query.include_deleted ?? '').toLowerCase()), limit: query.limit, }); } catch (error) { throw mapServiceError(error); } } async function listDatasets(user) { const { service } = await createServiceForUser(user); const datasets = await service.listDatasets(); return datasets.map((dataset) => ({ name: dataset.name, table: dataset.table, description: dataset.description, actions: dataset.actions, })); } async function assertPageOwner(user, pageId) { const pool = getPool(); if (pool) { const [rows] = await pool.query( `SELECT user_id FROM h5_publish_records WHERE page_id = ? AND status = 'online' ORDER BY published_at DESC LIMIT 1`, [pageId], ); const ownerId = rows[0]?.user_id; if (ownerId && ownerId === user.id) return; } const workspaceRoot = await resolveWorkspaceRoot(user); const policy = readPageAccessPolicy(workspaceRoot, pageId); if (policy?.ownerUserId === user.id) return; throw Object.assign(new Error('无权访问该页面数据'), { code: 'forbidden', status: 403 }); } async function listPageLogs(user, pageId, query = {}) { await assertPageOwner(user, pageId); const { workspaceRoot } = await createServiceForUser(user); const logs = listPageDataLogs(workspaceRoot, pageId, { limit: query.limit, offset: query.offset, }); return { pageId, logs, count: logs.length }; } return { getUserAuth, listRows, getSchema, getStats, insertRow, updateRow, softDeleteRow, restoreRow, exportDataset, listDatasets, listPageLogs, }; }