pediatric-ai-scribe-v3/src/utils/generatedImageLinks.js

34 lines
2.1 KiB
JavaScript

const { UUID, failure } = require('./generatedImages');
function references(text) {
const ids = new Set();
for (const match of String(text || '').matchAll(/\/api\/generated-images\/([a-zA-Z0-9%-]+)/g)) {
if (!UUID.test(match[1])) throw failure(400, 'Invalid generated image reference');
ids.add(match[1]);
}
return [...ids];
}
async function validateChat(db, payload, owner) {
const ids = new Set([...references(payload.generatedImage), ...references(payload.lastAnswer)]);
for (const job of payload.generatedImageJobs || []) ids.add(job.jobId);
for (const message of payload.messages) {
for (const job of message.imageJobs || []) ids.add(job.jobId);
for (const id of references(message.content)) ids.add(id);
}
if (!ids.size) return;
const rows = await db.query("SELECT id FROM generated_image_jobs WHERE id=ANY($1::uuid[]) AND owner_id=$2 AND workflow='clinical_assistant'", [[...ids], owner]);
if (rows.rows.length !== ids.size) throw failure(403, 'Saved image references must belong to this account and Clinical Assistant');
}
// Called INSIDE the content write transaction: publication and grants commit together.
async function validateLearning(client, body, owner, contentId) {
const ids = references(body);
if (!ids.length) return ids;
const rows = await client.query(`SELECT j.id FROM generated_image_jobs j WHERE j.id=ANY($1::uuid[]) AND j.workflow='learning_hub' AND j.stage='done'
AND (j.owner_id=$2 OR EXISTS (SELECT 1 FROM generated_image_links l WHERE l.asset_id=j.id AND l.content_id=$3)) FOR SHARE`, [ids, owner, contentId || null]);
if (rows.rows.length !== ids.length) throw failure(403, 'Only your Learning Hub assets, or assets already attached to this content, may be attached. Clinical/private-chat images cannot be published.');
return ids;
}
async function setLinks(client, contentId, ids) {
await client.query('DELETE FROM generated_image_links WHERE content_id=$1', [contentId]);
for (const id of ids) await client.query('INSERT INTO generated_image_links(asset_id,content_id) VALUES($1,$2)', [id, contentId]);
}
module.exports = { references, validateChat, validateLearning, setLinks };