Skip to content

Commit 27e8bf9

Browse files
authored
feat(api): get exams endpoint (freeCodeCamp#56727)
1 parent ed2b372 commit 27e8bf9

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

api/src/exam-environment/routes/exam-environment.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ describe('/exam-environment/', () => {
2424
setupServer();
2525
describe('Authenticated user with exam environment authorization token', () => {
2626
let superPost: ReturnType<typeof createSuperRequest>;
27+
let superGet: ReturnType<typeof createSuperRequest>;
2728
let examEnvironmentAuthorizationToken: string;
2829

2930
// Authenticate user
3031
beforeAll(async () => {
3132
const setCookies = await devLogin();
3233
superPost = createSuperRequest({ method: 'POST', setCookies });
34+
superGet = createSuperRequest({ method: 'GET', setCookies });
3335
await mock.seedEnvExam();
3436
// Add exam environment authorization token
3537
const res = await superPost('/user/exam-environment/token');
@@ -532,15 +534,43 @@ describe('/exam-environment/', () => {
532534
});
533535

534536
xdescribe('POST /exam-environment/screenshot', () => {});
537+
538+
describe('GET /exam-environment/exams', () => {
539+
it('should return 200', async () => {
540+
const res = await superGet('/exam-environment/exams').set(
541+
'exam-environment-authorization-token',
542+
examEnvironmentAuthorizationToken
543+
);
544+
expect(res.status).toBe(200);
545+
546+
expect(res.body).toStrictEqual({
547+
data: {
548+
exams: [
549+
{
550+
canTake: true,
551+
config: {
552+
name: mock.exam.config.name,
553+
note: mock.exam.config.note,
554+
totalTimeInMS: mock.exam.config.totalTimeInMS
555+
},
556+
id: mock.examId
557+
}
558+
]
559+
}
560+
});
561+
});
562+
});
535563
});
536564

537565
describe('Authenticated user without exam environment authorization token', () => {
538566
let superPost: ReturnType<typeof createSuperRequest>;
567+
let superGet: ReturnType<typeof createSuperRequest>;
539568

540569
// Authenticate user
541570
beforeAll(async () => {
542571
const setCookies = await devLogin();
543572
superPost = createSuperRequest({ method: 'POST', setCookies });
573+
superGet = createSuperRequest({ method: 'GET', setCookies });
544574
await mock.seedEnvExam();
545575
});
546576
describe('POST /exam-environment/exam/attempt', () => {
@@ -598,5 +628,16 @@ describe('/exam-environment/', () => {
598628
});
599629
});
600630
});
631+
632+
describe('GET /exam-environment/exams', () => {
633+
it('should return 403', async () => {
634+
const res = await superGet('/exam-environment/exams').set(
635+
'exam-environment-authorization-token',
636+
'invalid-token'
637+
);
638+
639+
expect(res.status).toBe(403);
640+
});
641+
});
601642
});
602643
});

api/src/exam-environment/routes/exam-environment.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ import { ERRORS } from '../utils/errors';
2323
*/
2424
export const examEnvironmentValidatedTokenRoutes: FastifyPluginCallbackTypebox =
2525
(fastify, _options, done) => {
26+
fastify.get(
27+
'/exam-environment/exams',
28+
{
29+
schema: schemas.examEnvironmentExams
30+
},
31+
getExams
32+
);
2633
fastify.post(
2734
'/exam-environment/exam/generated-exam',
2835
{
@@ -565,3 +572,37 @@ async function postScreenshotHandler(
565572
) {
566573
return reply.code(418);
567574
}
575+
576+
async function getExams(
577+
this: FastifyInstance,
578+
req: UpdateReqType<typeof schemas.examEnvironmentExams>,
579+
reply: FastifyReply
580+
) {
581+
const user = req.user!;
582+
const exams = await this.prisma.envExam.findMany({
583+
select: {
584+
id: true,
585+
config: true
586+
}
587+
});
588+
589+
const availableExams = exams.map(exam => {
590+
const isExamPrerequisitesMet = checkPrerequisites(user, true);
591+
592+
return {
593+
id: exam.id,
594+
config: {
595+
name: exam.config.name,
596+
note: exam.config.note,
597+
totalTimeInMS: exam.config.totalTimeInMS
598+
},
599+
canTake: isExamPrerequisitesMet
600+
};
601+
});
602+
603+
return reply.send({
604+
data: {
605+
exams: availableExams
606+
}
607+
});
608+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Type } from '@fastify/type-provider-typebox';
2+
import { STANDARD_ERROR } from '../utils/errors';
3+
export const examEnvironmentExams = {
4+
headers: Type.Object({
5+
'exam-environment-authorization-token': Type.String()
6+
}),
7+
response: {
8+
200: Type.Union([
9+
Type.Object({
10+
data: Type.Object({
11+
exams: Type.Array(
12+
Type.Object({
13+
id: Type.String(),
14+
config: Type.Object({
15+
name: Type.String(),
16+
note: Type.String(),
17+
totalTimeInMS: Type.Number()
18+
}),
19+
canTake: Type.Boolean()
20+
})
21+
)
22+
})
23+
}),
24+
STANDARD_ERROR
25+
])
26+
}
27+
};

api/src/exam-environment/schemas/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { examEnvironmentPostExamAttempt } from './exam-attempt';
22
export { examEnvironmentPostExamGeneratedExam } from './exam-generated-exam';
33
export { examEnvironmentPostScreenshot } from './screenshot';
44
export { examEnvironmentTokenVerify } from './token-verify';
5+
export { examEnvironmentExams } from './exams';

0 commit comments

Comments
 (0)