import Boom from '@hapi/boom'; import { db } from '../db/knex.js'; import { auditFromRequest } from '../middleware/audit.js'; import { submitConsentSchema } from '../schemas/consent.js'; /** * @param {unknown} value */ function parseJson(value) { if (typeof value === 'string') { return JSON.parse(value); } return value ?? null; } /** * @param {Record} row */ export function presentConsent(row) { return { id: row.id, participant_name: row.participant_name, consent_date: typeof row.consent_date === 'string' ? row.consent_date.slice(0, 10) : row.consent_date ? new Date(row.consent_date).toISOString().slice(0, 10) : null, answers: parseJson(row.answers), submitted_at: row.submitted_at, }; } /** * @param {number} userId */ export async function getConsentForUser(userId) { const row = await db('consents').where({ user_id: userId }).first(); return row ? presentConsent(row) : null; } /** * @param {import('@hapi/hapi').Request} request * @param {number} userId * @param {unknown} payload */ export async function submitConsent(request, userId, payload) { const existing = await db('consents').where({ user_id: userId }).first(); if (existing) { throw Boom.conflict('Consent has already been submitted'); } const application = await db('applications').where({ user_id: userId }).first(); if (!application) { throw Boom.badRequest('No application is linked to this account'); } const parsed = submitConsentSchema.safeParse(payload); if (!parsed.success) { const message = parsed.error.issues .map((issue) => `${issue.path.join('.') || 'body'}: ${issue.message}`) .join('; '); throw Boom.badRequest(message); } const now = new Date(); const [id] = await db('consents').insert({ user_id: userId, application_id: application.id, participant_name: parsed.data.participant_name, consent_date: parsed.data.consent_date, answers: JSON.stringify(parsed.data.answers), submitted_at: now, }); await db('users').where({ id: userId }).update({ name: parsed.data.participant_name, }); await auditFromRequest(request, { actorType: 'PHYSICIAN', actorId: userId, action: 'CONSENT_SUBMITTED', entityType: 'consents', entityId: id, }); const row = await db('consents').where({ id }).first(); return presentConsent(row); }