Files
freeCodeCamp/api/prisma/exam-environment.prisma
2025-12-04 15:18:16 +01:00

254 lines
9.6 KiB
Plaintext

/// An exam for the Exam Environment App as designed by the examiners
model ExamEnvironmentExam {
/// Globally unique exam id
id String @id @default(auto()) @map("_id") @db.ObjectId
/// All questions for a given exam
questionSets ExamEnvironmentQuestionSet[]
/// Configuration for exam metadata
config ExamEnvironmentConfig
/// 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
/// Version of the record
/// The default must be incremented by 1, if anything in the schema changes
version Int @default(3)
// Relations
generatedExams ExamEnvironmentGeneratedExam[]
examAttempts ExamEnvironmentExamAttempt[]
ExamEnvironmentChallenge ExamEnvironmentChallenge[]
}
/// A grouping of one or more questions of a given type
type ExamEnvironmentQuestionSet {
/// Unique question type id
id String @db.ObjectId
type ExamEnvironmentQuestionType
/// Content related to all questions in set
context String?
questions ExamEnvironmentMultipleChoiceQuestion[]
}
/// A multiple choice question for the Exam Environment App
type ExamEnvironmentMultipleChoiceQuestion {
/// Unique question id
id String @db.ObjectId
/// Main question paragraph
text String
/// Zero or more tags given to categorize a question
tags String[]
/// Optional audio for a question
audio ExamEnvironmentAudio?
/// Available possible answers for an exam
answers ExamEnvironmentAnswer[]
/// TODO Possible "deprecated_time" to remove after all exams could possibly have been taken
deprecated Boolean
}
/// Audio for an Exam Environment App multiple choice question
type ExamEnvironmentAudio {
/// Optional text for audio
captions String?
/// URL to audio file
///
/// Expected in the format: `<url>#t=<start_time_in_seconds>,<end_time_in_seconds>`
/// Where `start_time_in_seconds` and `end_time_in_seconds` are optional floats.
url String
}
/// Type of question for the Exam Environment App
enum ExamEnvironmentQuestionType {
/// Single question with one or more answers
MultipleChoice
/// Mass text
Dialogue
}
/// Answer for an Exam Environment App multiple choice question
type ExamEnvironmentAnswer {
/// Unique answer id
id String @db.ObjectId
/// Whether the answer is correct
isCorrect Boolean
/// Answer paragraph
text String
}
/// Configuration for an exam in the Exam Environment App
type ExamEnvironmentConfig {
/// Human-readable exam name
name String
/// Notes given about exam
note String
/// Category configuration for question selection
tags ExamEnvironmentTagConfig[]
/// Total time allocated for exam in seconds
totalTimeInS Int
/// Configuration for sets of questions
questionSets ExamEnvironmentQuestionSetConfig[]
/// Duration after exam completion before a retake is allowed in seconds
retakeTimeInS Int
/// Passing percent for the exam
passingPercent Float
}
/// Configuration for a set of questions in the Exam Environment App
type ExamEnvironmentQuestionSetConfig {
type ExamEnvironmentQuestionType
/// Number of this grouping of questions per exam
numberOfSet Int
/// Number of multiple choice questions per grouping matching this set config
numberOfQuestions Int
/// Number of correct answers given per multiple choice question
numberOfCorrectAnswers Int
/// Number of incorrect answers given per multiple choice question
numberOfIncorrectAnswers Int
}
/// Configuration for tags in the Exam Environment App
///
/// This configures the number of questions that should resolve to a given tag set criteria.
type ExamEnvironmentTagConfig {
/// Group of multiple choice question tags
group String[]
/// Number of multiple choice questions per exam that should meet the group criteria
numberOfQuestions Int
}
/// An attempt at an exam in the Exam Environment App
model ExamEnvironmentExamAttempt {
id String @id @default(auto()) @map("_id") @db.ObjectId
/// Foriegn key to user
userId String @db.ObjectId
/// Foreign key to exam
examId String @db.ObjectId
/// Foreign key to generated exam id
generatedExamId String @db.ObjectId
/// Un-enforced foreign key to moderation
examModerationId String? @db.ObjectId
questionSets ExamEnvironmentQuestionSetAttempt[]
/// Time exam was started
startTime DateTime
/// Version of the record
/// The default must be incremented by 1, if anything in the schema changes
version Int @default(4)
// Relations
user user @relation(fields: [userId], references: [id], onDelete: Cascade)
exam ExamEnvironmentExam @relation(fields: [examId], references: [id], onDelete: Cascade)
generatedExam ExamEnvironmentGeneratedExam @relation(fields: [generatedExamId], references: [id])
// Ideally, there could be a way to add a one-way optional relation here, but Prisma does not allow that:
// Error parsing attribute "@relation": The relation fields `examAttempt` on Model `ExamEnvironmentExamModeration` and `examModeration` on Model `ExamEnvironmentExamAttempt` both provide the `references` argument in the @relation attribute. You have to provide it only on one of the two fields.
// examModeration ExamEnvironmentExamModeration? @relation(fields: [examModerationId], references: [id])
examEnvironmentExamModeration ExamEnvironmentExamModeration?
}
type ExamEnvironmentQuestionSetAttempt {
id String @db.ObjectId
questions ExamEnvironmentMultipleChoiceQuestionAttempt[]
}
type ExamEnvironmentMultipleChoiceQuestionAttempt {
/// Foreign key to question
id String @db.ObjectId
/// An array of foreign keys to answers
answers String[] @db.ObjectId
/// Time answers to question were submitted
///
/// If the question is later revisited, this field is updated
submissionTime DateTime
}
/// A generated exam for the Exam Environment App
///
/// This is the user-facing information for an exam.
model ExamEnvironmentGeneratedExam {
id String @id @default(auto()) @map("_id") @db.ObjectId
/// Foreign key to exam
examId String @db.ObjectId
questionSets ExamEnvironmentGeneratedQuestionSet[]
/// If `deprecated`, the generation should not longer be considered for users
deprecated Boolean
/// Version of the record
/// The default must be incremented by 1, if anything in the schema changes
version Int @default(1)
// Relations
exam ExamEnvironmentExam @relation(fields: [examId], references: [id], onDelete: Cascade)
EnvExamAttempt ExamEnvironmentExamAttempt[]
}
type ExamEnvironmentGeneratedQuestionSet {
id String @db.ObjectId
questions ExamEnvironmentGeneratedMultipleChoiceQuestion[]
}
type ExamEnvironmentGeneratedMultipleChoiceQuestion {
/// Foreign key to question id
id String @db.ObjectId
/// Each item is a foreign key to an answer
answers String[] @db.ObjectId
}
/// A map between challenge ids and exam ids
///
/// This is expected to be used for relating challenge pages AND/OR certifications to exams
model ExamEnvironmentChallenge {
id String @id @default(auto()) @map("_id") @db.ObjectId
examId String @db.ObjectId
challengeId String @db.ObjectId
version Int @default(1)
exam ExamEnvironmentExam @relation(fields: [examId], references: [id], onDelete: Cascade)
}
model ExamEnvironmentAuthorizationToken {
/// An ObjectId is used to provide access to the created timestamp
id String @id @default(auto()) @map("_id") @db.ObjectId
/// Used to set an `expireAt` index to delete documents
expireAt DateTime @db.Date
userId String @unique @db.ObjectId
version Int @default(1)
// Relations
user user @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model ExamEnvironmentExamModeration {
id String @id @default(auto()) @map("_id") @db.ObjectId
/// Whether or not the item is approved
status ExamEnvironmentExamModerationStatus
/// Foreign key to exam attempt
examAttemptId String @unique @db.ObjectId
/// Optional feedback/note about the moderation decision
feedback String?
/// Date the exam attempt was moderated
moderationDate DateTime?
/// Foreign key to moderator. This is `null` until the item is moderated.
moderatorId String? @db.ObjectId
/// Date the exam attempt expired
submissionDate DateTime @default(now()) @db.Date
/// Whether the `challengeId` for the `ExamEnvironmentChallenge` has been awarded to the user
challengesAwarded Boolean @default(false)
/// Version of the record
/// The default must be incremented by 1, if anything in the schema changes
version Int @default(2)
// Relations
examAttempt ExamEnvironmentExamAttempt @relation(fields: [examAttemptId], references: [id], onDelete: Cascade)
}
enum ExamEnvironmentExamModerationStatus {
/// Attempt is determined to be valid
Approved
/// Attempt is determined to be invalid
Denied
/// Attempt has yet to be moderated
Pending
}