This commit is contained in:
@@ -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 }))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user