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 };