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

This commit is contained in:
silverpro89
2026-02-24 16:31:06 +07:00
parent d0f41920f7
commit 65820bb938
4 changed files with 207 additions and 16 deletions

View File

@@ -14,6 +14,8 @@ exports.createStory = async (req, res) => {
vocabulary = [],
context = [],
grade = [],
grade_number = 0,
type = 'story',
tag = []
} = req.body;
@@ -33,6 +35,8 @@ exports.createStory = async (req, res) => {
vocabulary,
context,
grade,
grade_number,
type,
tag
}, { transaction });
@@ -66,6 +70,9 @@ exports.getAllStories = async (req, res) => {
search,
grade_filter,
tag_filter,
type,
grade_start,
grade_end,
sort_by = 'created_at',
sort_order = 'DESC'
} = req.query;
@@ -78,7 +85,27 @@ exports.getAllStories = async (req, res) => {
where.name = { [Op.like]: `%${search}%` };
}
// Grade filter
// Type filter (exact match)
if (type) {
where.type = type;
}
// Grade number range filter
if (grade_start !== undefined && grade_end !== undefined) {
const s = parseInt(grade_start);
const e = parseInt(grade_end);
if (s === e) {
where.grade_number = s;
} else if (s < e) {
where.grade_number = { [Op.between]: [s, e] };
}
} else if (grade_start !== undefined) {
where.grade_number = { [Op.gte]: parseInt(grade_start) };
} else if (grade_end !== undefined) {
where.grade_number = { [Op.lte]: parseInt(grade_end) };
}
// Grade filter (legacy JSON array search)
if (grade_filter) {
where.grade = {
[Op.contains]: [grade_filter]
@@ -165,6 +192,8 @@ exports.updateStory = async (req, res) => {
vocabulary,
context,
grade,
grade_number,
type,
tag
} = req.body;
@@ -185,6 +214,8 @@ exports.updateStory = async (req, res) => {
if (vocabulary !== undefined) updateData.vocabulary = vocabulary;
if (context !== undefined) updateData.context = context;
if (grade !== undefined) updateData.grade = grade;
if (grade_number !== undefined) updateData.grade_number = grade_number;
if (type !== undefined) updateData.type = type;
if (tag !== undefined) updateData.tag = tag;
await story.update(updateData, { transaction });
@@ -245,23 +276,37 @@ exports.deleteStory = async (req, res) => {
*/
exports.getStoriesByGrade = async (req, res) => {
try {
const { grade } = req.query;
const { grade, start, end } = req.query;
if (!grade) {
const where = {};
// grade_number range search
if (start !== undefined && end !== undefined) {
const s = parseInt(start);
const e = parseInt(end);
if (s === e) {
where.grade_number = s;
} else if (s < e) {
where.grade_number = { [Op.between]: [s, e] };
}
} else if (start !== undefined) {
where.grade_number = { [Op.gte]: parseInt(start) };
} else if (end !== undefined) {
where.grade_number = { [Op.lte]: parseInt(end) };
} else if (grade) {
// Legacy: search by JSON array
where.grade = { [Op.contains]: [grade] };
} else {
return res.status(400).json({
success: false,
message: 'Grade parameter is required'
message: 'Provide grade, or start/end parameters'
});
}
const stories = await Story.findAll({
where: {
grade: {
[Op.contains]: [grade]
}
},
order: [['created_at', 'DESC']],
attributes: ['id', 'name', 'logo', 'grade', 'tag', 'created_at']
where,
order: [['grade_number', 'ASC'], ['created_at', 'DESC']],
attributes: ['id', 'name', 'logo', 'type', 'grade', 'grade_number', 'tag', 'created_at']
});
res.json({
@@ -320,6 +365,41 @@ exports.getStoriesByTag = async (req, res) => {
}
};
/**
* READ: Get stories by type
*/
exports.getStoriesByType = async (req, res) => {
try {
const { type } = req.query;
if (!type) {
return res.status(400).json({
success: false,
message: 'Type parameter is required'
});
}
const stories = await Story.findAll({
where: { type },
order: [['grade_number', 'ASC'], ['created_at', 'DESC']]
});
res.json({
success: true,
data: stories,
count: stories.length
});
} catch (error) {
console.error('Error fetching stories by type:', error);
res.status(500).json({
success: false,
message: 'Failed to fetch stories by type',
error: error.message
});
}
};
/**
* READ: Get story statistics
*/
@@ -327,12 +407,24 @@ exports.getStoryStats = async (req, res) => {
try {
const totalStories = await Story.count();
// Get all stories to analyze grades and tags
// Count by type (SQL GROUP BY)
const typeRows = await sequelize.query(
`SELECT type, COUNT(*) as count FROM stories GROUP BY type ORDER BY count DESC`,
{ type: sequelize.QueryTypes.SELECT }
);
// Count by grade_number (SQL GROUP BY)
const gradeNumberRows = await sequelize.query(
`SELECT grade_number, COUNT(*) as count FROM stories GROUP BY grade_number ORDER BY grade_number ASC`,
{ type: sequelize.QueryTypes.SELECT }
);
// Get all stories to analyze legacy grade array and tags
const allStories = await Story.findAll({
attributes: ['grade', 'tag']
});
// Count by grade
// Count by legacy grade array
const gradeStats = {};
allStories.forEach(story => {
if (story.grade && Array.isArray(story.grade)) {
@@ -356,6 +448,8 @@ exports.getStoryStats = async (req, res) => {
success: true,
data: {
total: totalStories,
by_type: typeRows.map(r => ({ type: r.type || 'story', count: parseInt(r.count) })),
by_grade_number: gradeNumberRows.map(r => ({ grade_number: r.grade_number, count: parseInt(r.count) })),
by_grade: Object.entries(gradeStats).map(([grade, count]) => ({ grade, count })),
by_tag: Object.entries(tagStats).map(([tag, count]) => ({ tag, count }))
}