diff --git a/api/__mocks__/env-exam.ts b/api/__mocks__/env-exam.ts index b30c24b0fbd..21c3e027c8b 100644 --- a/api/__mocks__/env-exam.ts +++ b/api/__mocks__/env-exam.ts @@ -339,7 +339,8 @@ export const exam: EnvExam = { id: examId, config, questionSets, - prerequisites: ['67112fe1c994faa2c26d0b1d'] + prerequisites: ['67112fe1c994faa2c26d0b1d'], + deprecated: false }; export async function seedEnvExam() { diff --git a/api/package.json b/api/package.json index bd21cd68af1..778fb5864c1 100644 --- a/api/package.json +++ b/api/package.json @@ -81,6 +81,8 @@ "postinstall": "prisma generate", "lint": "cd .. && eslint api/src --max-warnings 0", "generate-exams": "tsx src/exam-environment/generate/index.ts", + "deprecate-exam": "tsx src/exam-environment/generate/deprecate.ts", + "insert-exam": "tsx src/exam-environment/generate/insert.ts", "seed:env-exam": "tsx src/exam-environment/seed/index.ts" }, "version": "0.0.1" diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma index 79800993ecc..e17167205d1 100644 --- a/api/prisma/schema.prisma +++ b/api/prisma/schema.prisma @@ -166,6 +166,8 @@ model EnvExam { config EnvConfig /// ObjectIds for required challenges/blocks to take the exam prerequisites String[] @db.ObjectId + /// If `deprecated`, the exam should no longer be considered for users + deprecated Boolean // Relations generatedExams EnvGeneratedExam[] diff --git a/api/src/exam-environment/generate/deprecate.ts b/api/src/exam-environment/generate/deprecate.ts new file mode 100644 index 00000000000..5883fbe0835 --- /dev/null +++ b/api/src/exam-environment/generate/deprecate.ts @@ -0,0 +1,52 @@ +import { PrismaClient } from '@prisma/client'; +import { MONGOHQ_URL } from '../../utils/env'; + +const args = process.argv.slice(2); +const ENV_EXAM_ID = args[0]; + +if (!ENV_EXAM_ID) { + throw 'First argument must be the EnvExam _id'; +} + +const prisma = new PrismaClient({ + datasources: { + db: { + url: MONGOHQ_URL + } + } +}); + +async function main() { + console.info('Connecting to cluster...'); + await prisma.$connect(); + console.info('Connected.'); + + try { + await prisma.envExam.update({ + where: { + id: ENV_EXAM_ID + }, + data: { + deprecated: true + } + }); + console.info(`Exam "${ENV_EXAM_ID}" deprecated...`); + const res = await prisma.envGeneratedExam.updateMany({ + where: { + examId: ENV_EXAM_ID + }, + data: { + deprecated: true + } + }); + + console.info(`${res.count} generated exams deprecated...`); + } catch (e) { + console.error('Unable to deprecate exam due to:'); + console.error(e); + } + + console.info(`Finished deprecating exam.`); +} + +void main(); diff --git a/api/src/exam-environment/generate/insert.ts b/api/src/exam-environment/generate/insert.ts new file mode 100644 index 00000000000..248f6b78973 --- /dev/null +++ b/api/src/exam-environment/generate/insert.ts @@ -0,0 +1,43 @@ +import { readFile } from 'fs/promises'; +import { EnvExam, PrismaClient } from '@prisma/client'; +import { MONGOHQ_URL } from '../../utils/env'; + +const args = process.argv.slice(2); +const EXAM_JSON_PATH = args[0]; + +const prisma = new PrismaClient({ + datasources: { + db: { + url: MONGOHQ_URL + } + } +}); + +async function main() { + console.info('Connecting to cluster...'); + await prisma.$connect(); + console.info('Connected.'); + + if (!EXAM_JSON_PATH) { + throw 'First argument must be the file path to the exam'; + } + + const exam_str = await readFile(EXAM_JSON_PATH, 'utf-8'); + + const exam = JSON.parse(exam_str) as EnvExam; + + try { + const res = await prisma.envExam.create({ + data: exam + }); + + console.info( + `Exam "${res.config.name}" has been assigned id: "${res.id}".` + ); + } catch (e) { + console.error('Unable to insert exam due to:'); + console.error(e); + } +} + +void main(); diff --git a/api/src/exam-environment/routes/exam-environment.test.ts b/api/src/exam-environment/routes/exam-environment.test.ts index c153a045173..1b755e85215 100644 --- a/api/src/exam-environment/routes/exam-environment.test.ts +++ b/api/src/exam-environment/routes/exam-environment.test.ts @@ -570,7 +570,6 @@ describe('/exam-environment/', () => { 'exam-environment-authorization-token', examEnvironmentAuthorizationToken ); - expect(res.status).toBe(200); expect(res.body).toStrictEqual({ exams: [ @@ -586,6 +585,26 @@ describe('/exam-environment/', () => { } ] }); + + expect(res.status).toBe(200); + }); + + it('should not return any deprecated exams', async () => { + await fastifyTestInstance.prisma.envExam.update({ + where: { id: mock.examId }, + data: { deprecated: true } + }); + + const res = await superGet('/exam-environment/exams').set( + 'exam-environment-authorization-token', + examEnvironmentAuthorizationToken + ); + + expect(res.body).toStrictEqual({ + exams: [] + }); + + expect(res.status).toBe(200); }); }); }); diff --git a/api/src/exam-environment/routes/exam-environment.ts b/api/src/exam-environment/routes/exam-environment.ts index a9484e9c334..4d820a9c5a8 100644 --- a/api/src/exam-environment/routes/exam-environment.ts +++ b/api/src/exam-environment/routes/exam-environment.ts @@ -557,6 +557,9 @@ async function getExams( ) { const user = req.user!; const exams = await this.prisma.envExam.findMany({ + where: { + deprecated: false + }, select: { id: true, config: true, diff --git a/api/src/exam-environment/utils/exam.ts b/api/src/exam-environment/utils/exam.ts index 18e4188e5b9..889eefeeb5f 100644 --- a/api/src/exam-environment/utils/exam.ts +++ b/api/src/exam-environment/utils/exam.ts @@ -32,7 +32,7 @@ export function checkPrerequisites( export type UserExam = Omit< EnvExam, - 'questionSets' | 'config' | 'id' | 'prerequisites' + 'questionSets' | 'config' | 'id' | 'prerequisites' | 'deprecated' > & { config: Omit; questionSets: (Omit & {