2018-03-23 14:35:29 +00:00
|
|
|
const Joi = require('joi');
|
|
|
|
Joi.objectId = require('joi-objectid')(Joi);
|
|
|
|
|
2021-08-09 08:30:31 +00:00
|
|
|
const { challengeTypes } = require('../../client/utils/challenge-types');
|
2019-02-18 09:43:09 +00:00
|
|
|
|
2021-02-23 04:22:48 +00:00
|
|
|
const slugRE = new RegExp('^[a-z0-9-]+$');
|
2021-12-22 20:18:06 +00:00
|
|
|
const slugWithSlashRE = new RegExp('^[a-z0-9-/]+$');
|
2021-02-23 04:22:48 +00:00
|
|
|
|
2020-07-02 06:14:46 +00:00
|
|
|
const fileJoi = Joi.object().keys({
|
2021-08-12 18:48:28 +00:00
|
|
|
fileKey: Joi.string(),
|
2020-07-02 06:14:46 +00:00
|
|
|
ext: Joi.string(),
|
|
|
|
name: Joi.string(),
|
2020-06-09 09:41:26 +00:00
|
|
|
editableRegionBoundaries: [Joi.array().items(Joi.number())],
|
|
|
|
path: Joi.string(),
|
2021-05-05 09:11:57 +00:00
|
|
|
error: Joi.valid(null),
|
2020-06-09 09:41:26 +00:00
|
|
|
head: Joi.string().allow(''),
|
|
|
|
tail: Joi.string().allow(''),
|
|
|
|
seed: Joi.string().allow(''),
|
|
|
|
contents: Joi.string().allow(''),
|
2020-11-27 18:02:05 +00:00
|
|
|
id: Joi.string().allow(''),
|
2022-02-16 21:48:22 +00:00
|
|
|
history: Joi.array().items(Joi.string().allow(''))
|
2020-07-02 06:14:46 +00:00
|
|
|
});
|
|
|
|
|
2020-10-30 19:10:34 +00:00
|
|
|
const schema = Joi.object()
|
|
|
|
.keys({
|
2022-04-15 14:17:49 +00:00
|
|
|
block: Joi.string().regex(slugRE).required(),
|
2020-10-30 19:10:34 +00:00
|
|
|
blockId: Joi.objectId(),
|
|
|
|
challengeOrder: Joi.number(),
|
2021-04-28 15:18:54 +00:00
|
|
|
removeComments: Joi.bool(),
|
2021-12-20 18:36:31 +00:00
|
|
|
certification: Joi.string().regex(slugRE),
|
2022-01-06 13:26:54 +00:00
|
|
|
challengeType: Joi.number().min(0).max(14).required(),
|
2020-10-30 19:10:34 +00:00
|
|
|
checksum: Joi.number(),
|
2021-03-20 06:29:13 +00:00
|
|
|
// __commentCounts is only used to test the comment replacement
|
|
|
|
__commentCounts: Joi.object(),
|
2021-01-13 02:31:00 +00:00
|
|
|
// TODO: require this only for normal challenges, not certs
|
2021-02-23 04:22:48 +00:00
|
|
|
dashedName: Joi.string().regex(slugRE),
|
2020-10-30 19:10:34 +00:00
|
|
|
description: Joi.when('challengeType', {
|
2022-02-11 15:39:27 +00:00
|
|
|
is: [challengeTypes.step, challengeTypes.video],
|
2020-10-30 19:10:34 +00:00
|
|
|
then: Joi.string().allow(''),
|
|
|
|
otherwise: Joi.string().required()
|
|
|
|
}),
|
2021-08-12 18:48:28 +00:00
|
|
|
challengeFiles: Joi.array().items(fileJoi),
|
2020-10-30 19:10:34 +00:00
|
|
|
guideUrl: Joi.string().uri({ scheme: 'https' }),
|
2021-12-15 13:52:44 +00:00
|
|
|
hasEditableBoundaries: Joi.boolean(),
|
2021-06-15 15:37:13 +00:00
|
|
|
helpCategory: Joi.valid(
|
|
|
|
'JavaScript',
|
|
|
|
'HTML-CSS',
|
|
|
|
'Python',
|
2022-02-11 15:39:27 +00:00
|
|
|
'Backend Development'
|
2021-06-15 15:37:13 +00:00
|
|
|
),
|
2020-10-30 19:10:34 +00:00
|
|
|
videoUrl: Joi.string().allow(''),
|
|
|
|
forumTopicId: Joi.number(),
|
|
|
|
id: Joi.objectId().required(),
|
|
|
|
instructions: Joi.string().allow(''),
|
|
|
|
isComingSoon: Joi.bool(),
|
|
|
|
isLocked: Joi.bool(),
|
|
|
|
isPrivate: Joi.bool(),
|
2021-12-09 18:42:03 +00:00
|
|
|
notes: Joi.string().allow(''),
|
2020-10-30 19:10:34 +00:00
|
|
|
order: Joi.number(),
|
|
|
|
// video challenges only:
|
|
|
|
videoId: Joi.when('challengeType', {
|
|
|
|
is: challengeTypes.video,
|
|
|
|
then: Joi.string().required()
|
|
|
|
}),
|
2021-09-27 09:26:38 +00:00
|
|
|
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()
|
|
|
|
})
|
|
|
|
}),
|
2020-10-30 19:10:34 +00:00
|
|
|
question: Joi.object().keys({
|
2020-04-06 18:49:56 +00:00
|
|
|
text: Joi.string().required(),
|
2021-03-10 19:01:46 +00:00
|
|
|
answers: Joi.array().items(Joi.string()).required(),
|
2020-10-30 19:10:34 +00:00
|
|
|
solution: Joi.number().required()
|
2020-04-06 18:49:56 +00:00
|
|
|
}),
|
2020-10-30 19:10:34 +00:00
|
|
|
required: Joi.array().items(
|
|
|
|
Joi.object().keys({
|
|
|
|
link: Joi.string(),
|
|
|
|
raw: Joi.bool(),
|
|
|
|
src: Joi.string(),
|
|
|
|
crossDomain: Joi.bool()
|
|
|
|
})
|
|
|
|
),
|
2021-12-22 20:18:06 +00:00
|
|
|
solutions: Joi.array().items(Joi.array().items(fileJoi).min(1)),
|
|
|
|
superBlock: Joi.string().regex(slugWithSlashRE),
|
2020-10-30 19:10:34 +00:00
|
|
|
superOrder: Joi.number(),
|
|
|
|
suborder: Joi.number(),
|
|
|
|
tests: Joi.array().items(
|
|
|
|
// public challenges
|
|
|
|
Joi.object().keys({
|
2020-11-27 18:02:05 +00:00
|
|
|
id: Joi.string().allow(''),
|
2020-10-30 19:10:34 +00:00
|
|
|
text: Joi.string().required(),
|
2021-03-10 19:01:46 +00:00
|
|
|
testString: Joi.string().allow('').required()
|
2020-10-30 19:10:34 +00:00
|
|
|
}),
|
|
|
|
// 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(''),
|
2021-02-11 12:40:32 +00:00
|
|
|
title: Joi.string().required(),
|
2021-06-15 15:37:13 +00:00
|
|
|
translationPending: Joi.bool().required(),
|
|
|
|
url: Joi.when('challengeType', {
|
2022-02-11 15:39:27 +00:00
|
|
|
is: [challengeTypes.codeAllyPractice, challengeTypes.codeAllyCert],
|
2021-06-15 15:37:13 +00:00
|
|
|
then: Joi.string().required()
|
2021-10-13 11:47:59 +00:00
|
|
|
}),
|
|
|
|
usesMultifileEditor: Joi.boolean()
|
2020-10-30 19:10:34 +00:00
|
|
|
})
|
|
|
|
.xor('helpCategory', 'isPrivate');
|
2018-10-30 15:48:54 +00:00
|
|
|
|
2020-10-01 13:50:43 +00:00
|
|
|
exports.challengeSchemaValidator = () => {
|
2021-05-05 09:11:57 +00:00
|
|
|
return challenge => schema.validate(challenge);
|
2018-03-23 14:35:29 +00:00
|
|
|
};
|