From 27e8bf9da04911993682e4ee431c0059953a41d5 Mon Sep 17 00:00:00 2001 From: Sem Bauke Date: Fri, 18 Oct 2024 20:43:28 +0200 Subject: [PATCH] feat(api): get exams endpoint (#56727) --- .../routes/exam-environment.test.ts | 41 +++++++++++++++++++ .../routes/exam-environment.ts | 41 +++++++++++++++++++ api/src/exam-environment/schemas/exams.ts | 27 ++++++++++++ api/src/exam-environment/schemas/index.ts | 1 + 4 files changed, 110 insertions(+) create mode 100644 api/src/exam-environment/schemas/exams.ts diff --git a/api/src/exam-environment/routes/exam-environment.test.ts b/api/src/exam-environment/routes/exam-environment.test.ts index 4e76c4140fd..d9532617f7e 100644 --- a/api/src/exam-environment/routes/exam-environment.test.ts +++ b/api/src/exam-environment/routes/exam-environment.test.ts @@ -24,12 +24,14 @@ describe('/exam-environment/', () => { setupServer(); describe('Authenticated user with exam environment authorization token', () => { let superPost: ReturnType; + let superGet: ReturnType; let examEnvironmentAuthorizationToken: string; // Authenticate user beforeAll(async () => { const setCookies = await devLogin(); superPost = createSuperRequest({ method: 'POST', setCookies }); + superGet = createSuperRequest({ method: 'GET', setCookies }); await mock.seedEnvExam(); // Add exam environment authorization token const res = await superPost('/user/exam-environment/token'); @@ -532,15 +534,43 @@ describe('/exam-environment/', () => { }); xdescribe('POST /exam-environment/screenshot', () => {}); + + describe('GET /exam-environment/exams', () => { + it('should return 200', async () => { + const res = await superGet('/exam-environment/exams').set( + 'exam-environment-authorization-token', + examEnvironmentAuthorizationToken + ); + expect(res.status).toBe(200); + + expect(res.body).toStrictEqual({ + data: { + exams: [ + { + canTake: true, + config: { + name: mock.exam.config.name, + note: mock.exam.config.note, + totalTimeInMS: mock.exam.config.totalTimeInMS + }, + id: mock.examId + } + ] + } + }); + }); + }); }); describe('Authenticated user without exam environment authorization token', () => { let superPost: ReturnType; + let superGet: ReturnType; // Authenticate user beforeAll(async () => { const setCookies = await devLogin(); superPost = createSuperRequest({ method: 'POST', setCookies }); + superGet = createSuperRequest({ method: 'GET', setCookies }); await mock.seedEnvExam(); }); describe('POST /exam-environment/exam/attempt', () => { @@ -598,5 +628,16 @@ describe('/exam-environment/', () => { }); }); }); + + describe('GET /exam-environment/exams', () => { + it('should return 403', async () => { + const res = await superGet('/exam-environment/exams').set( + 'exam-environment-authorization-token', + 'invalid-token' + ); + + expect(res.status).toBe(403); + }); + }); }); }); diff --git a/api/src/exam-environment/routes/exam-environment.ts b/api/src/exam-environment/routes/exam-environment.ts index b17da669557..5dfac214030 100644 --- a/api/src/exam-environment/routes/exam-environment.ts +++ b/api/src/exam-environment/routes/exam-environment.ts @@ -23,6 +23,13 @@ import { ERRORS } from '../utils/errors'; */ export const examEnvironmentValidatedTokenRoutes: FastifyPluginCallbackTypebox = (fastify, _options, done) => { + fastify.get( + '/exam-environment/exams', + { + schema: schemas.examEnvironmentExams + }, + getExams + ); fastify.post( '/exam-environment/exam/generated-exam', { @@ -565,3 +572,37 @@ async function postScreenshotHandler( ) { return reply.code(418); } + +async function getExams( + this: FastifyInstance, + req: UpdateReqType, + reply: FastifyReply +) { + const user = req.user!; + const exams = await this.prisma.envExam.findMany({ + select: { + id: true, + config: true + } + }); + + const availableExams = exams.map(exam => { + const isExamPrerequisitesMet = checkPrerequisites(user, true); + + return { + id: exam.id, + config: { + name: exam.config.name, + note: exam.config.note, + totalTimeInMS: exam.config.totalTimeInMS + }, + canTake: isExamPrerequisitesMet + }; + }); + + return reply.send({ + data: { + exams: availableExams + } + }); +} diff --git a/api/src/exam-environment/schemas/exams.ts b/api/src/exam-environment/schemas/exams.ts new file mode 100644 index 00000000000..899ae04dd61 --- /dev/null +++ b/api/src/exam-environment/schemas/exams.ts @@ -0,0 +1,27 @@ +import { Type } from '@fastify/type-provider-typebox'; +import { STANDARD_ERROR } from '../utils/errors'; +export const examEnvironmentExams = { + headers: Type.Object({ + 'exam-environment-authorization-token': Type.String() + }), + response: { + 200: Type.Union([ + Type.Object({ + data: Type.Object({ + exams: Type.Array( + Type.Object({ + id: Type.String(), + config: Type.Object({ + name: Type.String(), + note: Type.String(), + totalTimeInMS: Type.Number() + }), + canTake: Type.Boolean() + }) + ) + }) + }), + STANDARD_ERROR + ]) + } +}; diff --git a/api/src/exam-environment/schemas/index.ts b/api/src/exam-environment/schemas/index.ts index 254e1018ae9..7cf2e1616c0 100644 --- a/api/src/exam-environment/schemas/index.ts +++ b/api/src/exam-environment/schemas/index.ts @@ -2,3 +2,4 @@ export { examEnvironmentPostExamAttempt } from './exam-attempt'; export { examEnvironmentPostExamGeneratedExam } from './exam-generated-exam'; export { examEnvironmentPostScreenshot } from './screenshot'; export { examEnvironmentTokenVerify } from './token-verify'; +export { examEnvironmentExams } from './exams';