95 lines
2.4 KiB
JavaScript
95 lines
2.4 KiB
JavaScript
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<string, unknown>} 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);
|
|
}
|