186 lines
5.7 KiB
TypeScript
186 lines
5.7 KiB
TypeScript
import Joi from 'joi';
|
|
|
|
// Multi-language validation schema
|
|
const multiLangSchema = Joi.object({
|
|
th: Joi.string().required().messages({
|
|
'any.required': 'Thai text is required'
|
|
}),
|
|
en: Joi.string().required().messages({
|
|
'any.required': 'English text is required'
|
|
})
|
|
}).required();
|
|
|
|
const multiLangOptionalSchema = Joi.object({
|
|
th: Joi.string().optional(),
|
|
en: Joi.string().optional()
|
|
}).optional();
|
|
|
|
// ============================================
|
|
// Chapter Validators
|
|
// ============================================
|
|
|
|
/**
|
|
* Validator for creating a chapter
|
|
*/
|
|
export const CreateChapterValidator = Joi.object({
|
|
title: multiLangSchema.messages({
|
|
'any.required': 'Title is required'
|
|
}),
|
|
description: multiLangOptionalSchema,
|
|
sort_order: Joi.number().integer().min(0).optional()
|
|
});
|
|
|
|
/**
|
|
* Validator for updating a chapter
|
|
*/
|
|
export const UpdateChapterValidator = Joi.object({
|
|
title: multiLangOptionalSchema,
|
|
description: multiLangOptionalSchema,
|
|
sort_order: Joi.number().integer().min(0).optional(),
|
|
is_published: Joi.boolean().optional()
|
|
});
|
|
|
|
/**
|
|
* Validator for reordering a chapter
|
|
*/
|
|
export const ReorderChapterValidator = Joi.object({
|
|
sort_order: Joi.number().integer().min(0).required().messages({
|
|
'any.required': 'Sort order is required',
|
|
'number.min': 'Sort order must be at least 0'
|
|
})
|
|
});
|
|
|
|
// ============================================
|
|
// Lesson Validators
|
|
// ============================================
|
|
|
|
/**
|
|
* Validator for creating a lesson
|
|
*/
|
|
export const CreateLessonValidator = Joi.object({
|
|
title: multiLangSchema.messages({
|
|
'any.required': 'Title is required'
|
|
}),
|
|
content: multiLangOptionalSchema,
|
|
type: Joi.string().valid('VIDEO', 'QUIZ').required().messages({
|
|
'any.only': 'Type must be either VIDEO or QUIZ',
|
|
'any.required': 'Type is required'
|
|
}),
|
|
sort_order: Joi.number().integer().min(0).optional()
|
|
});
|
|
|
|
/**
|
|
* Validator for updating a lesson
|
|
*/
|
|
export const UpdateLessonValidator = Joi.object({
|
|
title: multiLangOptionalSchema,
|
|
content: multiLangOptionalSchema,
|
|
duration_minutes: Joi.number().min(0).optional().messages({
|
|
'number.min': 'Duration must be at least 0'
|
|
}),
|
|
sort_order: Joi.number().integer().min(0).optional(),
|
|
prerequisite_lesson_ids: Joi.array().items(Joi.number().integer().positive()).optional(),
|
|
is_published: Joi.boolean().optional()
|
|
});
|
|
|
|
/**
|
|
* Validator for reordering lessons
|
|
*/
|
|
export const ReorderLessonsValidator = Joi.object({
|
|
lesson_id: Joi.number().integer().positive().required().messages({
|
|
'any.required': 'Lesson ID is required'
|
|
}),
|
|
sort_order: Joi.number().integer().min(0).required().messages({
|
|
'any.required': 'Sort order is required'
|
|
})
|
|
});
|
|
|
|
// ============================================
|
|
// Quiz Question Validators
|
|
// ============================================
|
|
|
|
/**
|
|
* Validator for quiz choice
|
|
*/
|
|
const QuizChoiceValidator = Joi.object({
|
|
text: multiLangSchema.messages({
|
|
'any.required': 'Choice text is required'
|
|
}),
|
|
is_correct: Joi.boolean().required().messages({
|
|
'any.required': 'is_correct is required'
|
|
}),
|
|
sort_order: Joi.number().integer().min(0).optional()
|
|
});
|
|
|
|
/**
|
|
* Validator for adding a question to a quiz
|
|
*/
|
|
export const AddQuestionValidator = Joi.object({
|
|
question: multiLangSchema.messages({
|
|
'any.required': 'Question is required'
|
|
}),
|
|
explanation: multiLangOptionalSchema,
|
|
question_type: Joi.string()
|
|
.valid('MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER')
|
|
.required()
|
|
.messages({
|
|
'any.only': 'Question type must be MULTIPLE_CHOICE, TRUE_FALSE, or SHORT_ANSWER',
|
|
'any.required': 'Question type is required'
|
|
}),
|
|
sort_order: Joi.number().integer().min(0).optional(),
|
|
choices: Joi.array().items(QuizChoiceValidator).min(1).optional().messages({
|
|
'array.min': 'At least one choice is required for multiple choice questions'
|
|
})
|
|
});
|
|
|
|
/**
|
|
* Validator for updating a question
|
|
*/
|
|
export const UpdateQuestionValidator = Joi.object({
|
|
question: multiLangOptionalSchema,
|
|
explanation: multiLangOptionalSchema,
|
|
question_type: Joi.string()
|
|
.valid('MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER')
|
|
.optional()
|
|
.messages({
|
|
'any.only': 'Question type must be MULTIPLE_CHOICE, TRUE_FALSE, or SHORT_ANSWER'
|
|
}),
|
|
sort_order: Joi.number().integer().min(0).optional(),
|
|
choices: Joi.array().items(QuizChoiceValidator).min(1).optional().messages({
|
|
'array.min': 'At least one choice is required'
|
|
})
|
|
});
|
|
|
|
/**
|
|
* Validator for reordering a question
|
|
*/
|
|
export const ReorderQuestionValidator = Joi.object({
|
|
sort_order: Joi.number().integer().min(0).required().messages({
|
|
'any.required': 'Sort order is required',
|
|
'number.min': 'Sort order must be at least 0'
|
|
})
|
|
});
|
|
|
|
// ============================================
|
|
// Quiz Settings Validator
|
|
// ============================================
|
|
|
|
/**
|
|
* Validator for updating quiz settings
|
|
*/
|
|
export const UpdateQuizValidator = Joi.object({
|
|
title: multiLangOptionalSchema,
|
|
description: multiLangOptionalSchema,
|
|
passing_score: Joi.number().min(0).max(100).optional().messages({
|
|
'number.min': 'Passing score must be at least 0',
|
|
'number.max': 'Passing score must not exceed 100'
|
|
}),
|
|
time_limit: Joi.number().min(0).optional().messages({
|
|
'number.min': 'Time limit must be at least 0'
|
|
}),
|
|
shuffle_questions: Joi.boolean().optional(),
|
|
shuffle_choices: Joi.boolean().optional(),
|
|
show_answers_after_completion: Joi.boolean().optional(),
|
|
is_skippable: Joi.boolean().optional(),
|
|
allow_multiple_attempts: Joi.boolean().optional()
|
|
});
|