Files
memind/server/portal-mindspace-space-routes.mjs

134 lines
4.8 KiB
JavaScript

function assertRouter(api) {
if (
!api ||
typeof api.get !== 'function' ||
typeof api.post !== 'function'
) {
throw new Error(
'attachPortalMindSpaceSpaceRoutes requires an Express-compatible router',
);
}
}
export function attachPortalMindSpaceSpaceRoutes(
api,
{
getMindSpace = () => null,
getScheduleService = () => null,
getMindSpaceCleanup = () => null,
getMindSpaceAudit = () => null,
ensureMindSpaceEnabled = () => false,
sendData = (res, _req, data) => res.json({ data }),
sendError = (res, _req, status, code, message) =>
res.status(status).json({ error: { code, message } }),
handleMindSpaceError = (_res, _req, error) => {
throw error;
},
} = {},
) {
assertRouter(api);
api.get('/mindspace/v1/space', async (req, res) => {
const mindSpace = getMindSpace();
if (!mindSpace || !ensureMindSpaceEnabled(res, req)) return;
const space = await mindSpace.getSpace(req.currentUser.id);
if (!space) {
return sendError(res, req, 404, 'resource_not_found', '用户空间不存在');
}
return sendData(res, req, space);
});
api.post('/mindspace/v1/schedule/reminders/:reminderId/ignore', async (req, res) => {
const scheduleService = getScheduleService();
if (!ensureMindSpaceEnabled(res, req) || !scheduleService) {
return sendError(res, req, 503, 'feature_disabled', '日程服务未启用');
}
try {
const reminder = await scheduleService.cancelReminder({
userId: req.currentUser.id,
reminderId: req.params.reminderId,
});
return sendData(res, req, reminder);
} catch (err) {
const message = err instanceof Error ? err.message : '忽略提醒失败';
return sendError(res, req, 400, 'invalid_schedule_input', message);
}
});
api.post('/mindspace/v1/schedule/reminders/bulk-delete', async (req, res) => {
const scheduleService = getScheduleService();
if (!ensureMindSpaceEnabled(res, req) || !scheduleService) {
return sendError(res, req, 503, 'feature_disabled', '日程服务未启用');
}
try {
const ids = Array.isArray(req.body?.ids) ? req.body.ids.map(String) : [];
const deleted = await scheduleService.deleteReminders({
userId: req.currentUser.id,
reminderIds: ids,
});
return sendData(res, req, { deleted });
} catch (err) {
const message = err instanceof Error ? err.message : '删除提醒失败';
return sendError(res, req, 400, 'invalid_schedule_input', message);
}
});
api.get('/mindspace/v1/space/quota', async (req, res) => {
const mindSpace = getMindSpace();
if (!mindSpace) return res.status(503).json({ message: 'MindSpace 未启用' });
const quota = await mindSpace.getQuota(req.currentUser.id);
if (!quota) return res.status(404).json({ message: '用户空间不存在' });
return res.json({ data: quota });
});
api.get('/mindspace/v1/space/categories', async (req, res) => {
const mindSpace = getMindSpace();
if (!mindSpace) return res.status(503).json({ message: 'MindSpace 未启用' });
const categories = await mindSpace.listCategories(req.currentUser.id);
if (!categories) return res.status(404).json({ message: '用户空间不存在' });
return res.json({ data: categories });
});
api.get('/mindspace/v1/space/cleanup', async (req, res) => {
const mindSpaceCleanup = getMindSpaceCleanup();
if (!mindSpaceCleanup || !ensureMindSpaceEnabled(res, req)) return;
try {
const username = req.currentUser.username ?? req.currentUser.slug;
const items = await mindSpaceCleanup.listCandidates(req.currentUser.id, username);
const totalBytes = items.reduce((sum, item) => sum + item.sizeBytes, 0);
return sendData(res, req, { items, totalBytes });
} catch (error) {
return handleMindSpaceError(res, req, error);
}
});
api.post('/mindspace/v1/space/cleanup', async (req, res) => {
const mindSpaceCleanup = getMindSpaceCleanup();
if (!mindSpaceCleanup || !ensureMindSpaceEnabled(res, req)) return;
try {
const username = req.currentUser.username ?? req.currentUser.slug;
const itemIds = Array.isArray(req.body?.item_ids) ? req.body.item_ids : [];
const result = await mindSpaceCleanup.runCleanup(
req.currentUser.id,
username,
itemIds,
);
const quota = await getMindSpace().getQuota(req.currentUser.id);
await getMindSpaceAudit()?.write({
userId: req.currentUser.id,
action: 'space.cleanup',
objectType: 'space',
objectId: req.currentUser.id,
ip: req.ip,
detail: {
removedCount: result.removedCount,
freedBytes: result.freedBytes,
},
});
return sendData(res, req, { ...result, quota });
} catch (error) {
return handleMindSpaceError(res, req, error);
}
});
}