From 741e330d2e06ad37e251fd586d2e1098e918f118 Mon Sep 17 00:00:00 2001 From: realmayus Date: Mon, 20 Jan 2025 15:38:15 +0100 Subject: [PATCH 1/2] add match dissolve reason for when students are deactivated due to not having turned in a certificate of conduct --- common/notification/hooks.ts | 2 +- common/student/activation.ts | 5 +++-- graphql/me/mutation.ts | 2 +- .../redact-inactive-accounts/deactivate-inactive-accounts.ts | 2 +- .../20250120143543_no_co_c_dissolve_reason/migration.sql | 2 ++ prisma/schema.prisma | 1 + 6 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 prisma/migrations/20250120143543_no_co_c_dissolve_reason/migration.sql diff --git a/common/notification/hooks.ts b/common/notification/hooks.ts index e79d695d5..23300d85c 100644 --- a/common/notification/hooks.ts +++ b/common/notification/hooks.ts @@ -13,7 +13,7 @@ registerStudentHook( 'deactivate-student', 'Account gets deactivated, matches are dissolved, courses are cancelled', async (student) => { - await deactivateStudent(student, true, 'missing coc'); + await deactivateStudent(student, true, true, 'missing coc'); } // the hook does not send out a notification again, the user already knows that their account was deactivated ); diff --git a/common/student/activation.ts b/common/student/activation.ts index fdeb4567e..e09ba972e 100644 --- a/common/student/activation.ts +++ b/common/student/activation.ts @@ -11,7 +11,7 @@ import { userForStudent } from '../user'; import { CertificateState } from '../certificate'; import { removeAllPushSubcriptions } from '../notification/channels/push'; -export async function deactivateStudent(student: Student, silent = false, reason?: string) { +export async function deactivateStudent(student: Student, silent = false, noCoC = false, reason?: string) { if (!student.active) { throw new Error('Student was already deactivated'); } @@ -32,7 +32,8 @@ export async function deactivateStudent(student: Student, silent = false, reason }, }); for (const match of matches) { - await dissolveMatch(match, [dissolve_reason.accountDeactivated], student, dissolved_by_enum.student); + const dissolveReason = noCoC ? dissolve_reason.accountDeactivatedNoCoC : dissolve_reason.accountDeactivated; + await dissolveMatch(match, [dissolveReason], student, dissolved_by_enum.student); } // Remove any pending certificates, so that they no longer show up in pupil dashboards diff --git a/graphql/me/mutation.ts b/graphql/me/mutation.ts index c820b6cae..763199805 100644 --- a/graphql/me/mutation.ts +++ b/graphql/me/mutation.ts @@ -175,7 +175,7 @@ export class MutateMeResolver { if (isSessionStudent(context)) { const student = await getSessionStudent(context); - const updatedStudent = await deactivateStudent(student, false, reason); + const updatedStudent = await deactivateStudent(student, false, false, reason); const roles: Role[] = []; await evaluateStudentRoles(updatedStudent, roles); diff --git a/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts b/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts index 13f91ca50..e843193fe 100644 --- a/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts +++ b/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts @@ -23,7 +23,7 @@ export async function deactivateInactiveAccounts() { } for (const student of persons.students) { - await deactivateStudent(student, true, DEACTIVATION_MESSAGE); + await deactivateStudent(student, true, false, DEACTIVATION_MESSAGE); } logger.info('End deactivating inactive accounts'); diff --git a/prisma/migrations/20250120143543_no_co_c_dissolve_reason/migration.sql b/prisma/migrations/20250120143543_no_co_c_dissolve_reason/migration.sql new file mode 100644 index 000000000..a29c67431 --- /dev/null +++ b/prisma/migrations/20250120143543_no_co_c_dissolve_reason/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "dissolve_reason" ADD VALUE 'accountDeactivatedNoCoC'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fe0c451f0..b70cfd4b5 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1555,6 +1555,7 @@ enum dissolved_by_enum { enum dissolve_reason { accountDeactivated // The account was deactivated, causing any active matches to be dissolved automatically + accountDeactivatedNoCoC // The account was deactivated because the student did not hand in a Certificate of Conduct ghosted // "Mein:e Lernpartner:in hat sich nicht zurückgemeldet" noMoreHelpNeeded // "Mein:e Lernpartner:in benötigt keine Unterstützung mehr" and "Ich benötige keine Unterstützung mehr" isOfNoHelp // "Ich konnte meinem/meiner Lernpartner:in nicht behilflich sein" and "Mein:e Lernpartner:in konnte mir nicht behilflich sein" From 576648baebbbddf62aa0e00c9ca62e0af25980d0 Mon Sep 17 00:00:00 2001 From: realmayus Date: Wed, 22 Jan 2025 13:45:31 +0100 Subject: [PATCH 2/2] change function signature to allow passing dissolveReason[] --- common/notification/hooks.ts | 3 ++- common/student/activation.ts | 10 +++++++--- graphql/me/mutation.ts | 2 +- .../deactivate-inactive-accounts.ts | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common/notification/hooks.ts b/common/notification/hooks.ts index 23300d85c..3016fb1eb 100644 --- a/common/notification/hooks.ts +++ b/common/notification/hooks.ts @@ -8,12 +8,13 @@ import { prisma } from '../prisma'; import { userForStudent } from '../user'; import * as Notification from '../../common/notification'; import { SpecificNotificationContext } from './actions'; +import { dissolve_reason } from '@prisma/client'; registerStudentHook( 'deactivate-student', 'Account gets deactivated, matches are dissolved, courses are cancelled', async (student) => { - await deactivateStudent(student, true, true, 'missing coc'); + await deactivateStudent(student, true, 'missing coc', [dissolve_reason.accountDeactivatedNoCoC]); } // the hook does not send out a notification again, the user already knows that their account was deactivated ); diff --git a/common/student/activation.ts b/common/student/activation.ts index e09ba972e..4420c8fef 100644 --- a/common/student/activation.ts +++ b/common/student/activation.ts @@ -11,7 +11,12 @@ import { userForStudent } from '../user'; import { CertificateState } from '../certificate'; import { removeAllPushSubcriptions } from '../notification/channels/push'; -export async function deactivateStudent(student: Student, silent = false, noCoC = false, reason?: string) { +export async function deactivateStudent( + student: Student, + silent = false, + reason?: string, + dissolveReasons: dissolve_reason[] = [dissolve_reason.accountDeactivated] +) { if (!student.active) { throw new Error('Student was already deactivated'); } @@ -32,8 +37,7 @@ export async function deactivateStudent(student: Student, silent = false, noCoC }, }); for (const match of matches) { - const dissolveReason = noCoC ? dissolve_reason.accountDeactivatedNoCoC : dissolve_reason.accountDeactivated; - await dissolveMatch(match, [dissolveReason], student, dissolved_by_enum.student); + await dissolveMatch(match, dissolveReasons, student, dissolved_by_enum.student); } // Remove any pending certificates, so that they no longer show up in pupil dashboards diff --git a/graphql/me/mutation.ts b/graphql/me/mutation.ts index 763199805..c820b6cae 100644 --- a/graphql/me/mutation.ts +++ b/graphql/me/mutation.ts @@ -175,7 +175,7 @@ export class MutateMeResolver { if (isSessionStudent(context)) { const student = await getSessionStudent(context); - const updatedStudent = await deactivateStudent(student, false, false, reason); + const updatedStudent = await deactivateStudent(student, false, reason); const roles: Role[] = []; await evaluateStudentRoles(updatedStudent, roles); diff --git a/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts b/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts index e843193fe..13f91ca50 100644 --- a/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts +++ b/jobs/periodic/redact-inactive-accounts/deactivate-inactive-accounts.ts @@ -23,7 +23,7 @@ export async function deactivateInactiveAccounts() { } for (const student of persons.students) { - await deactivateStudent(student, true, false, DEACTIVATION_MESSAGE); + await deactivateStudent(student, true, DEACTIVATION_MESSAGE); } logger.info('End deactivating inactive accounts');