From edb8c7b723c1caff686f1312552c0d79f83fed6f Mon Sep 17 00:00:00 2001 From: Markus Brueckner Date: Mon, 13 Jan 2025 09:25:26 +0100 Subject: [PATCH] fix serious issue where deleting a participant from one survey would delete them from all --- src/routes/(app)/+page.svelte | 2 +- .../(app)/survey/[surveyId]/+page.svelte | 23 +++++++++++++------ .../survey/[surveyId]/edit/+page.server.ts | 13 +++++++---- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte index 108340e..5a30e66 100644 --- a/src/routes/(app)/+page.svelte +++ b/src/routes/(app)/+page.svelte @@ -40,7 +40,7 @@ {survey.title} ({survey.fillRate.filled}/{survey.fillRate.expected}) - {#if survey.fillRate.filled === survey.fillRate.expected} + {#if survey.fillRate.filled === survey.fillRate.expected && survey.fillRate.expected > 0} {/if} diff --git a/src/routes/(app)/survey/[surveyId]/+page.svelte b/src/routes/(app)/survey/[surveyId]/+page.svelte index 91cc3fb..ae024e0 100644 --- a/src/routes/(app)/survey/[surveyId]/+page.svelte +++ b/src/routes/(app)/survey/[surveyId]/+page.svelte @@ -17,13 +17,22 @@ let { data }: { data: PageData } = $props(); - const diagramData = data.skills.flatMap((skill) => - data.participants.map((participant) => ({ - skill: skill.title, - participant: participant.id, - rating: participant.answers.find((answer) => answer.skillId === skill.id)?.rating - })) - ); + const diagramData = data.skills.flatMap((skill) => { + if (data.participants.length > 0) { + return data.participants.map((participant) => ({ + skill: skill.title, + participant: participant.id, + rating: participant.answers.find((answer) => answer.skillId === skill.id)?.rating + })); + } else { + // fallback pseudo participant because empty diagram data will break the diagram and make the survey page unaccessible + return { + skill: skill.title, + participant: -1, + rating: undefined + }; + } + }); function copyLinkToClipboard(link: string) { navigator.clipboard.writeText(link); diff --git a/src/routes/(app)/survey/[surveyId]/edit/+page.server.ts b/src/routes/(app)/survey/[surveyId]/edit/+page.server.ts index 0e20af7..4883557 100644 --- a/src/routes/(app)/survey/[surveyId]/edit/+page.server.ts +++ b/src/routes/(app)/survey/[surveyId]/edit/+page.server.ts @@ -5,7 +5,7 @@ import debug from 'debug'; import { fromFormData } from '$lib/survey'; import { db } from '../../../../../db'; import { surveyAccessTable, surveyAnswersTable, surveySkillsTable, surveysTable } from '../../../../../db/schema'; -import { eq, inArray } from 'drizzle-orm'; +import { eq, inArray, and } from 'drizzle-orm'; import { addParticipant, addSkill, loadSurveyData } from '../../../../../db/survey'; const log = debug('survey:admin:edit'); @@ -58,10 +58,13 @@ export const actions = { // update the participants where applicable (unchanged participants are left untouched) const deletedParticipants = survey.participants.filter(participant => !participants.includes(participant.email)); const newParticipants = participants.filter(email => !survey.participants.some(candidate => candidate.email === email)); - // delete all participants no longer part of the survey - await db.delete(surveyAccessTable).where(inArray(surveyAccessTable.recepientEmail, deletedParticipants.map(participant => participant.email))); - // delete answers from deleted participants - await db.delete(surveyAnswersTable).where(inArray(surveyAnswersTable.participantId, deletedParticipants.map(participant => participant.id))); + // delete all participants no longer part of the survey (this should also delete their answers via cascade delete) + await db.delete(surveyAccessTable).where( + and( + eq(surveyAccessTable.surveyId, survey.id), + inArray(surveyAccessTable.recepientEmail, deletedParticipants.map(participant => participant.email)) + ) + ); // add any new participants for (const newParticipant of newParticipants) { await addParticipant(survey.id, newParticipant);