freeCodeCamp/curriculum/schema/challengeSchema.js
Sem Bauke df53c7778c
feat: integrate The Odin Project (#48617)
* feat: integrate the odin project

* feat: add assignment to markdown parser

* feat: add assignment logic

* fix: doe not always show assignment block

* fix: some other stuff

* fix: introdiction to html and css questions

* fix: remove assignments after first question

* fix: update snapshots and tests

* feat: create rest of HTML foundation course structure

* feat: meta file

* feat: add descriptions to 'html boiler plate' questions

* feat: add description for 'working with text and list items'

* fix: multiple logic issues

* fix: make linter happy

* feat: add description for 'links and images' questions

* fix: add assignments to Joi schema

* fix: tests

* fix: schema

* fix: add help category

* fix: change to possessive wording

* fix: set upcoming change to true in meta file

* fix: spell unordered and ordered correctly

* fix: switch order in meta

* fix: spell boilerplate correctly

* feat: add final project

* chore: add more tests to the final project

* fix: question spelling

* Apply suggestions from code review

Co-authored-by: Naomi Carrigan <[email protected]>

* Apply suggestions from code review

Co-authored-by: Naomi Carrigan <[email protected]>

* Apply suggestions from code review

Co-authored-by: Naomi Carrigan <[email protected]>

* Apply suggestions from code review

Co-authored-by: Naomi Carrigan <[email protected]>

* Apply suggestions from code review

Co-authored-by: Naomi Carrigan <[email protected]>

* Apply suggestions from code review

Co-authored-by: Naomi Carrigan <[email protected]>

* fix: translation

* Update client/i18n/locales/english/translations.json

Co-authored-by: Oliver Eyton-Williams <[email protected]>

* fix: create new challenge type

* fix: get the new challenge type working and remove ol css

* fix: translation location

* fix: add challenge type to epic

* fix: set correct video

* fix: max challengeType number

* fix: spelling/grammar errors in project

* fix: check if anchor tags is empty

* Apply suggestions from code review

Co-authored-by: Oliver Eyton-Williams <[email protected]>

* Update tools/challenge-parser/parser/plugins/add-video-question.js

Co-authored-by: Oliver Eyton-Williams <[email protected]>

* chore: multiple suggestions

* chore: separate assignments into different plugin

* Apply suggestions from code review

Co-authored-by: Kristofer Koishigawa <[email protected]>

* fix: dubble answer header after review

* fix: issue with Gatsby hopefully

* fix: add assignments to Gatsby's Challenge schema

* Update curriculum/schema/challengeSchema.js

Co-authored-by: Oliver Eyton-Williams <[email protected]>

Co-authored-by: Naomi Carrigan <[email protected]>
Co-authored-by: Oliver Eyton-Williams <[email protected]>
Co-authored-by: Kristofer Koishigawa <[email protected]>
2023-01-19 14:55:26 +02:00

127 lines
3.9 KiB
JavaScript

const Joi = require('joi');
Joi.objectId = require('joi-objectid')(Joi);
const { challengeTypes } = require('../../client/utils/challenge-types');
const slugRE = new RegExp('^[a-z0-9-]+$');
const slugWithSlashRE = new RegExp('^[a-z0-9-/]+$');
const fileJoi = Joi.object().keys({
fileKey: Joi.string(),
ext: Joi.string(),
name: Joi.string(),
editableRegionBoundaries: [Joi.array().items(Joi.number())],
path: Joi.string(),
error: Joi.valid(null),
head: Joi.string().allow(''),
tail: Joi.string().allow(''),
seed: Joi.string().allow(''),
contents: Joi.string().allow(''),
id: Joi.string().allow(''),
history: Joi.array().items(Joi.string().allow(''))
});
const schema = Joi.object()
.keys({
block: Joi.string().regex(slugRE).required(),
blockId: Joi.objectId(),
challengeOrder: Joi.number(),
removeComments: Joi.bool(),
certification: Joi.string().regex(slugRE),
challengeType: Joi.number().min(0).max(15).required(),
checksum: Joi.number(),
// __commentCounts is only used to test the comment replacement
__commentCounts: Joi.object(),
// TODO: require this only for normal challenges, not certs
dashedName: Joi.string().regex(slugRE),
description: Joi.when('challengeType', {
is: [challengeTypes.step, challengeTypes.video],
then: Joi.string().allow(''),
otherwise: Joi.string().required()
}),
challengeFiles: Joi.array().items(fileJoi),
guideUrl: Joi.string().uri({ scheme: 'https' }),
hasEditableBoundaries: Joi.boolean(),
helpCategory: Joi.valid(
'JavaScript',
'HTML-CSS',
'Python',
'Backend Development'
),
videoUrl: Joi.string().allow(''),
forumTopicId: Joi.number(),
id: Joi.objectId().required(),
instructions: Joi.string().allow(''),
isComingSoon: Joi.bool(),
isLocked: Joi.bool(),
isPrivate: Joi.bool(),
notes: Joi.string().allow(''),
order: Joi.number(),
// video challenges only:
videoId: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.string().required()
}),
videoLocaleIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
espanol: Joi.string(),
italian: Joi.string(),
portuguese: Joi.string()
})
}),
bilibiliIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
aid: Joi.number().required(),
bvid: Joi.string().required(),
cid: Joi.number().required()
})
}),
question: Joi.object().keys({
text: Joi.string().required(),
answers: Joi.array().items(Joi.string()).required(),
solution: Joi.number().required()
}),
required: Joi.array().items(
Joi.object().keys({
link: Joi.string(),
raw: Joi.bool(),
src: Joi.string(),
crossDomain: Joi.bool()
})
),
assignments: Joi.array().items(Joi.string()),
solutions: Joi.array().items(Joi.array().items(fileJoi).min(1)),
superBlock: Joi.string().regex(slugWithSlashRE),
superOrder: Joi.number(),
suborder: Joi.number(),
tests: Joi.array().items(
// public challenges
Joi.object().keys({
id: Joi.string().allow(''),
text: Joi.string().required(),
testString: Joi.string().allow('').required()
}),
// our tests used in certification verification
Joi.object().keys({
id: Joi.string().required(),
title: Joi.string().required()
})
),
template: Joi.string().allow(''),
time: Joi.string().allow(''),
title: Joi.string().required(),
translationPending: Joi.bool().required(),
url: Joi.when('challengeType', {
is: [challengeTypes.codeAllyPractice, challengeTypes.codeAllyCert],
then: Joi.string().required()
}),
usesMultifileEditor: Joi.boolean()
})
.xor('helpCategory', 'isPrivate');
exports.challengeSchemaValidator = () => {
return challenge => schema.validate(challenge);
};