feat: introduce Joi validation schemas and integrate them across various controllers for categories, lessons, courses, chapters, announcements, and admin course approvals.
This commit is contained in:
parent
c5aa195b13
commit
b56f604890
14 changed files with 553 additions and 28 deletions
186
Backend/src/validators/ChaptersLesson.validator.ts
Normal file
186
Backend/src/validators/ChaptersLesson.validator.ts
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
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()
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue