From fa7d8ddbd929620a0e538194bfc90af62f7100ab Mon Sep 17 00:00:00 2001 From: Gobot1234 Date: Wed, 24 Apr 2024 12:17:40 +0100 Subject: [PATCH] feat: prevent reps signing in on shift without compulsory training --- apps/anvil/src/shared/constants/ErrorCodes.ts | 31 +++++------ apps/anvil/src/sign-in/sign-in.service.ts | 52 +++++++++++++------ packages/errors/index.ts | 31 +++++------ 3 files changed, 69 insertions(+), 45 deletions(-) diff --git a/apps/anvil/src/shared/constants/ErrorCodes.ts b/apps/anvil/src/shared/constants/ErrorCodes.ts index 8df92db..d23d35a 100644 --- a/apps/anvil/src/shared/constants/ErrorCodes.ts +++ b/apps/anvil/src/shared/constants/ErrorCodes.ts @@ -1,22 +1,23 @@ /** If an error can feasibly be hit by the UI it should have an associated error code for checking against on the front end */ export enum ErrorCodes { //#region sign in - not_registered = 0, - already_registered = 1, - ldap_not_found = 2, - already_signed_in_to_location = 3, - queue_full = 4, - location_full_and_queue_disabled = 5, - agreement_not_signed = 6, - not_in_queue = 7, - agreement_already_signed = 8, - not_rep = 9, - not_signed_in = 10, - queue_disabled = 11, - user_has_active_infractions = 12, + not_registered, + already_registered, + ldap_not_found, + already_signed_in_to_location, + queue_full, + location_full_and_queue_disabled, + agreement_not_signed, + not_in_queue, + agreement_already_signed, + not_rep, + not_signed_in, + queue_disabled, + user_has_active_infractions, + compulsory_training_missing, //#endregion //#region training - interactable_not_found = 13, - user_trying_to_complete_rep_training = 14, + interactable_not_found, + user_trying_to_complete_rep_training, //#endregion } diff --git a/apps/anvil/src/sign-in/sign-in.service.ts b/apps/anvil/src/sign-in/sign-in.service.ts index 8c30199..33a2ab1 100644 --- a/apps/anvil/src/sign-in/sign-in.service.ts +++ b/apps/anvil/src/sign-in/sign-in.service.ts @@ -468,30 +468,52 @@ export class SignInService implements OnModuleInit { async repSignIn(location: Location, ucard_number: number, reason_id: string) { const { reason, reason_name } = await this.verifySignInReason(reason_id, ucard_number, /* is_rep */ true); - if (reason_name !== REP_ON_SHIFT) { + if (reason_name !== REP_ON_SHIFT && !this.outOfHours()) { await this.preSignInChecks(location, ucard_number); } + // TODO this should be client side? + const user = e.assert_exists( + e.select(e.users.Rep, () => ({ + filter_single: { ucard_number }, + })), + ); + + const compulsory = e.select(e.training.Training, (training) => ({ + filter: e.op( + training.compulsory, + "and", + e.op(e.cast(e.training.TrainingLocation, location.toUpperCase()), "in", training.locations), + ), + })); + + const missing = await this.dbService.query( + e.select(e.op(compulsory, "except", user.training), () => ({ name: true, id: true })), + ); + + if (missing) { + throw new BadRequestException({ + message: `Rep hasn't completed compulsory on shift-trainings. Missing: ${missing + .map((training) => training.name) + .join(", ")}`, + code: ErrorCodes.compulsory_training_missing, + }); + } + try { await this.dbService.query( - e.select( - e.insert(e.sign_in.SignIn, { - location: castLocation(location), - user: e.assert_exists( - e.select(e.users.Rep, () => ({ - filter_single: { ucard_number }, - })), - ), - tools: [], - reason, - signed_out: false, - }), - ), + e.insert(e.sign_in.SignIn, { + location: castLocation(location), + user, + tools: [], + reason, + signed_out: false, + }), ); } catch (error) { if (error instanceof CardinalityViolationError) { throw new BadRequestException({ - message: `User ${ucard_number} already signed in`, + message: `Rep ${ucard_number} already signed in`, code: ErrorCodes.already_signed_in_to_location, }); } diff --git a/packages/errors/index.ts b/packages/errors/index.ts index 8df92db..d23d35a 100644 --- a/packages/errors/index.ts +++ b/packages/errors/index.ts @@ -1,22 +1,23 @@ /** If an error can feasibly be hit by the UI it should have an associated error code for checking against on the front end */ export enum ErrorCodes { //#region sign in - not_registered = 0, - already_registered = 1, - ldap_not_found = 2, - already_signed_in_to_location = 3, - queue_full = 4, - location_full_and_queue_disabled = 5, - agreement_not_signed = 6, - not_in_queue = 7, - agreement_already_signed = 8, - not_rep = 9, - not_signed_in = 10, - queue_disabled = 11, - user_has_active_infractions = 12, + not_registered, + already_registered, + ldap_not_found, + already_signed_in_to_location, + queue_full, + location_full_and_queue_disabled, + agreement_not_signed, + not_in_queue, + agreement_already_signed, + not_rep, + not_signed_in, + queue_disabled, + user_has_active_infractions, + compulsory_training_missing, //#endregion //#region training - interactable_not_found = 13, - user_trying_to_complete_rep_training = 14, + interactable_not_found, + user_trying_to_complete_rep_training, //#endregion }