@@ -24,6 +24,20 @@ import { isObjectID } from '../../utils/validation.js';
2424 */
2525export const examEnvironmentValidatedTokenRoutes : FastifyPluginCallbackTypebox =
2626 ( fastify , _options , done ) => {
27+ fastify . setErrorHandler ( ( error , req , res ) => {
28+ // If the error does not match the format {code: string; message: string}, coerce into:
29+ if (
30+ ! Object . hasOwnProperty . call ( error , 'code' ) ||
31+ ! Object . hasOwnProperty . call ( error , 'message' )
32+ ) {
33+ const logger = fastify . log . child ( { req, res } ) ;
34+ logger . error ( error , 'Unhandled error in exam environment routes.' ) ;
35+ const str = JSON . stringify ( error ) ;
36+ res . code ( 500 ) ;
37+ res . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( str ) ) ;
38+ }
39+ } ) ;
40+
2741 fastify . get (
2842 '/exam-environment/exams' ,
2943 {
@@ -182,7 +196,16 @@ async function postExamGeneratedExamHandler(
182196 reply : FastifyReply
183197) {
184198 const logger = this . log . child ( { req } ) ;
185- logger . info ( { userId : req . user ?. id } ) ;
199+ const user = req . user ;
200+
201+ if ( ! user ) {
202+ logger . error ( 'No user found in request.' ) ;
203+ this . Sentry . captureException ( 'No user found in request.' ) ;
204+ void reply . code ( 500 ) ;
205+ return reply . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( 'No user found.' ) ) ;
206+ }
207+
208+ logger . info ( { userId : user . id } ) ;
186209 // Get exam from DB
187210 const examId = req . body . examId ;
188211 const maybeExam = await mapErr (
@@ -218,7 +241,6 @@ async function postExamGeneratedExamHandler(
218241 }
219242
220243 // Check user has completed prerequisites
221- const user = req . user ! ;
222244 const isExamPrerequisitesMet = checkPrerequisites ( user , exam . prerequisites ) ;
223245
224246 if ( ! isExamPrerequisitesMet ) {
@@ -521,10 +543,18 @@ async function postExamAttemptHandler(
521543 reply : FastifyReply
522544) {
523545 const logger = this . log . child ( { req } ) ;
524- logger . info ( { userId : req . user ?. id } ) ;
525- const { attempt } = req . body ;
546+ const user = req . user ;
526547
527- const user = req . user ! ;
548+ if ( ! user ) {
549+ logger . error ( 'No user found in request.' ) ;
550+ this . Sentry . captureException ( 'No user found in request.' ) ;
551+ void reply . code ( 500 ) ;
552+ return reply . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( 'No user found.' ) ) ;
553+ }
554+
555+ logger . info ( { userId : user . id } ) ;
556+
557+ const { attempt } = req . body ;
528558
529559 const maybeAttempts = await mapErr (
530560 this . prisma . examEnvironmentExamAttempt . findMany ( {
@@ -651,23 +681,25 @@ async function postExamAttemptHandler(
651681 ) ;
652682
653683 if ( maybeValidExamAttempt . hasError ) {
654- logger . warn (
655- { validExamAttemptError : maybeValidExamAttempt . error } ,
656- 'Invalid exam attempt.'
657- ) ;
658- // As attempt is invalid, create moderation record to investigate
659- await this . prisma . examEnvironmentExamModeration . create ( {
660- data : {
684+ const message =
685+ maybeValidExamAttempt . error instanceof Error
686+ ? maybeValidExamAttempt . error . message
687+ : 'Unknown attempt validation error' ;
688+ logger . warn ( { validExamAttemptError : message } , 'Invalid exam attempt.' ) ;
689+ // As attempt is invalid, create moderation record to investigate or update existing record
690+ await this . prisma . examEnvironmentExamModeration . upsert ( {
691+ where : { examAttemptId : latestAttempt . id } ,
692+ create : {
661693 examAttemptId : latestAttempt . id ,
662- status : ExamEnvironmentExamModerationStatus . Pending
694+ status : ExamEnvironmentExamModerationStatus . Pending ,
695+ feedback : message
696+ } ,
697+ update : {
698+ feedback : message
663699 }
664700 } ) ;
665701
666702 void reply . code ( 400 ) ;
667- const message =
668- maybeValidExamAttempt . error instanceof Error
669- ? maybeValidExamAttempt . error . message
670- : 'Unknown attempt validation error' ;
671703 return reply . send ( ERRORS . FCC_EINVAL_EXAM_ENVIRONMENT_EXAM_ATTEMPT ( message ) ) ;
672704 }
673705
@@ -704,9 +736,17 @@ export async function getExams(
704736 reply : FastifyReply
705737) {
706738 const logger = this . log . child ( { req } ) ;
707- logger . info ( { userId : req . user ?. id } ) ;
739+ const user = req . user ;
740+
741+ if ( ! user ) {
742+ logger . error ( 'No user found in request.' ) ;
743+ this . Sentry . captureException ( 'No user found in request.' ) ;
744+ void reply . code ( 500 ) ;
745+ return reply . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( 'No user found.' ) ) ;
746+ }
747+
748+ logger . info ( { userId : user . id } ) ;
708749
709- const user = req . user ! ;
710750 const maybeExams = await mapErr (
711751 this . prisma . examEnvironmentExam . findMany ( {
712752 where : {
@@ -869,9 +909,16 @@ export async function getExamAttemptsHandler(
869909 reply : FastifyReply
870910) {
871911 const logger = this . log . child ( { req } ) ;
872- logger . info ( { userId : req . user ?. id } ) ;
912+ const user = req . user ;
873913
874- const user = req . user ! ;
914+ if ( ! user ) {
915+ logger . error ( 'No user found in request.' ) ;
916+ this . Sentry . captureException ( 'No user found in request.' ) ;
917+ void reply . code ( 500 ) ;
918+ return reply . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( 'No user found.' ) ) ;
919+ }
920+
921+ logger . info ( { userId : user . id } ) ;
875922
876923 // Send all relevant exam attempts
877924 const envExamAttempts = [ ] ;
@@ -929,9 +976,16 @@ export async function getExamAttemptHandler(
929976 reply : FastifyReply
930977) {
931978 const logger = this . log . child ( { req } ) ;
932- logger . info ( { userId : req . user ?. id } ) ;
979+ const user = req . user ;
980+
981+ if ( ! user ) {
982+ logger . error ( 'No user found in request.' ) ;
983+ this . Sentry . captureException ( 'No user found in request.' ) ;
984+ void reply . code ( 500 ) ;
985+ return reply . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( 'No user found.' ) ) ;
986+ }
987+ logger . info ( { userId : user . id } ) ;
933988
934- const user = req . user ! ;
935989 const { attemptId } = req . params ;
936990
937991 // If attempt id is given, only return that attempt
@@ -988,8 +1042,15 @@ export async function getExamAttemptsByExamIdHandler(
9881042 reply : FastifyReply
9891043) {
9901044 const logger = this . log . child ( { req } ) ;
1045+ const user = req . user ;
1046+
1047+ if ( ! user ) {
1048+ logger . error ( 'No user found in request.' ) ;
1049+ this . Sentry . captureException ( 'No user found in request.' ) ;
1050+ void reply . code ( 500 ) ;
1051+ return reply . send ( ERRORS . FCC_ERR_UNKNOWN_STATE ( 'No user found.' ) ) ;
1052+ }
9911053
992- const user = req . user ! ;
9931054 const { examId } = req . params ;
9941055
9951056 logger . info ( { examId, userId : user . id } ) ;
0 commit comments