update
All checks were successful
Deploy to Production / deploy (push) Successful in 20s

This commit is contained in:
Ken
2026-02-27 09:38:39 +07:00
parent 9af45a7875
commit 6287a019e3
16 changed files with 2032 additions and 18 deletions

View File

@@ -1,5 +1,7 @@
const { Story, sequelize } = require('../models');
const { Op } = require('sequelize');
const { Lesson, LessonStory } = require('../models');
const { cacheUtils } = require('../config/redis');
/**
* CREATE: Add new story
@@ -733,3 +735,213 @@ exports.getStoryGuide = async (req, res) => {
});
}
};
/**
* Lấy danh sách lessons sử dụng story này
*/
exports.getLessonsByStory = async (req, res) => {
try {
const { storyId } = req.params;
const { page = 1, limit = 20 } = req.query;
const offset = (parseInt(page) - 1) * parseInt(limit);
const cacheKey = `story:${storyId}:lessons:${page}:${limit}`;
const cached = await cacheUtils.get(cacheKey);
if (cached) {
return res.json({
success: true,
data: cached,
cached: true,
});
}
// Check if story exists
const story = await Story.findByPk(storyId);
if (!story) {
return res.status(404).json({
success: false,
message: 'Story not found',
});
}
// Get lessons with pivot data
const { count, rows } = await Lesson.findAndCountAll({
include: [
{
model: Story,
as: 'stories',
where: { id: storyId },
through: {
attributes: ['display_order', 'is_required'],
},
attributes: [],
},
],
limit: parseInt(limit),
offset: parseInt(offset),
order: [[{ model: Story, as: 'stories' }, LessonStory, 'display_order', 'ASC']],
});
const result = {
story: {
id: story.id,
name: story.name,
type: story.type,
},
lessons: rows.map(lesson => ({
...lesson.toJSON(),
display_order: lesson.stories[0]?.LessonStory?.display_order,
is_required: lesson.stories[0]?.LessonStory?.is_required,
})),
pagination: {
total: count,
page: parseInt(page),
limit: parseInt(limit),
totalPages: Math.ceil(count / parseInt(limit)),
},
};
await cacheUtils.set(cacheKey, result, 1800);
res.json({
success: true,
data: result,
cached: false,
});
} catch (error) {
console.error('Error fetching lessons by story:', error);
res.status(500).json({
success: false,
message: 'Failed to fetch lessons',
error: error.message,
});
}
};
/**
* Thêm lesson vào story (alternative way)
*/
exports.addLessonToStory = async (req, res) => {
try {
const { storyId } = req.params;
const { lesson_id, display_order = 0, is_required = true } = req.body;
// Validate required fields
if (!lesson_id) {
return res.status(400).json({
success: false,
message: 'lesson_id is required',
});
}
// Check if story exists
const story = await Story.findByPk(storyId);
if (!story) {
return res.status(404).json({
success: false,
message: 'Story not found',
});
}
// Check if lesson exists
const lesson = await Lesson.findByPk(lesson_id);
if (!lesson) {
return res.status(404).json({
success: false,
message: 'Lesson not found',
});
}
// Check if relationship already exists
const existing = await LessonStory.findOne({
where: {
lesson_id: lesson_id,
story_id: storyId,
},
});
if (existing) {
return res.status(400).json({
success: false,
message: 'Lesson đã sử dụng story này',
});
}
// Create relationship
const lessonStory = await LessonStory.create({
lesson_id: lesson_id,
story_id: storyId,
display_order,
is_required,
});
// Clear cache
await cacheUtils.deletePattern(`story:${storyId}:lessons:*`);
await cacheUtils.deletePattern(`lesson:${lesson_id}:stories:*`);
res.status(201).json({
success: true,
message: 'Lesson đã được thêm vào story',
data: lessonStory,
});
} catch (error) {
console.error('Error adding lesson to story:', error);
res.status(500).json({
success: false,
message: 'Failed to add lesson to story',
error: error.message,
});
}
};
/**
* Xóa lesson khỏi story
*/
exports.removeLessonFromStory = async (req, res) => {
try {
const { storyId, lessonId } = req.params;
// Check if story exists
const story = await Story.findByPk(storyId);
if (!story) {
return res.status(404).json({
success: false,
message: 'Story not found',
});
}
// Find relationship
const lessonStory = await LessonStory.findOne({
where: {
lesson_id: lessonId,
story_id: storyId,
},
});
if (!lessonStory) {
return res.status(404).json({
success: false,
message: 'Lesson không sử dụng story này',
});
}
await lessonStory.destroy();
// Clear cache
await cacheUtils.deletePattern(`story:${storyId}:lessons:*`);
await cacheUtils.deletePattern(`lesson:${lessonId}:stories:*`);
res.json({
success: true,
message: 'Lesson đã được xóa khỏi story',
});
} catch (error) {
console.error('Error removing lesson from story:', error);
res.status(500).json({
success: false,
message: 'Failed to remove lesson from story',
error: error.message,
});
}
};