update
This commit is contained in:
374
controllers/gameController.js
Normal file
374
controllers/gameController.js
Normal file
@@ -0,0 +1,374 @@
|
||||
const { Game } = require('../models');
|
||||
const { cacheUtils } = require('../config/redis');
|
||||
|
||||
/**
|
||||
* Game Controller - Quản lý trò chơi giáo dục
|
||||
*/
|
||||
class GameController {
|
||||
/**
|
||||
* Get all games with pagination
|
||||
*/
|
||||
async getAllGames(req, res, next) {
|
||||
try {
|
||||
const { page = 1, limit = 20, type, is_active, is_premium, difficulty_level } = req.query;
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const cacheKey = `games:list:${page}:${limit}:${type || 'all'}:${is_active || 'all'}:${is_premium || 'all'}:${difficulty_level || 'all'}`;
|
||||
|
||||
const cached = await cacheUtils.get(cacheKey);
|
||||
if (cached) {
|
||||
return res.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
});
|
||||
}
|
||||
|
||||
const where = {};
|
||||
if (type) where.type = type;
|
||||
if (is_active !== undefined) where.is_active = is_active === 'true';
|
||||
if (is_premium !== undefined) where.is_premium = is_premium === 'true';
|
||||
if (difficulty_level) where.difficulty_level = difficulty_level;
|
||||
|
||||
const { count, rows } = await Game.findAndCountAll({
|
||||
where,
|
||||
limit: parseInt(limit),
|
||||
offset: parseInt(offset),
|
||||
order: [['display_order', 'ASC'], ['rating', 'DESC']],
|
||||
});
|
||||
|
||||
const result = {
|
||||
games: rows,
|
||||
pagination: {
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
totalPages: Math.ceil(count / limit),
|
||||
},
|
||||
};
|
||||
|
||||
await cacheUtils.set(cacheKey, result, 1800);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result,
|
||||
cached: false,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get game by ID
|
||||
*/
|
||||
async getGameById(req, res, next) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const cacheKey = `game:${id}`;
|
||||
|
||||
const cached = await cacheUtils.get(cacheKey);
|
||||
if (cached) {
|
||||
return res.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
});
|
||||
}
|
||||
|
||||
const game = await Game.findByPk(id);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Game not found',
|
||||
});
|
||||
}
|
||||
|
||||
await cacheUtils.set(cacheKey, game, 3600);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: game,
|
||||
cached: false,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new game
|
||||
*/
|
||||
async createGame(req, res, next) {
|
||||
try {
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
url,
|
||||
thumbnail,
|
||||
type,
|
||||
config,
|
||||
is_active,
|
||||
is_premium,
|
||||
min_grade,
|
||||
max_grade,
|
||||
difficulty_level,
|
||||
display_order,
|
||||
} = req.body;
|
||||
|
||||
// Validate required fields
|
||||
if (!title || !url || !type) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'title, url, and type are required',
|
||||
});
|
||||
}
|
||||
|
||||
const game = await Game.create({
|
||||
title,
|
||||
description,
|
||||
url,
|
||||
thumbnail,
|
||||
type,
|
||||
config: config || {},
|
||||
is_active: is_active !== undefined ? is_active : true,
|
||||
is_premium: is_premium !== undefined ? is_premium : false,
|
||||
min_grade,
|
||||
max_grade,
|
||||
difficulty_level,
|
||||
display_order: display_order || 0,
|
||||
play_count: 0,
|
||||
});
|
||||
|
||||
// Clear cache
|
||||
await cacheUtils.deletePattern('games:*');
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: game,
|
||||
message: 'Game created successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update game
|
||||
*/
|
||||
async updateGame(req, res, next) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
url,
|
||||
thumbnail,
|
||||
type,
|
||||
config,
|
||||
is_active,
|
||||
is_premium,
|
||||
min_grade,
|
||||
max_grade,
|
||||
difficulty_level,
|
||||
display_order,
|
||||
rating,
|
||||
} = req.body;
|
||||
|
||||
const game = await Game.findByPk(id);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Game not found',
|
||||
});
|
||||
}
|
||||
|
||||
await game.update({
|
||||
...(title !== undefined && { title }),
|
||||
...(description !== undefined && { description }),
|
||||
...(url !== undefined && { url }),
|
||||
...(thumbnail !== undefined && { thumbnail }),
|
||||
...(type !== undefined && { type }),
|
||||
...(config !== undefined && { config }),
|
||||
...(is_active !== undefined && { is_active }),
|
||||
...(is_premium !== undefined && { is_premium }),
|
||||
...(min_grade !== undefined && { min_grade }),
|
||||
...(max_grade !== undefined && { max_grade }),
|
||||
...(difficulty_level !== undefined && { difficulty_level }),
|
||||
...(display_order !== undefined && { display_order }),
|
||||
...(rating !== undefined && { rating }),
|
||||
});
|
||||
|
||||
// Clear cache
|
||||
await cacheUtils.deletePattern('games:*');
|
||||
await cacheUtils.deletePattern(`game:${id}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: game,
|
||||
message: 'Game updated successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete game
|
||||
*/
|
||||
async deleteGame(req, res, next) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const game = await Game.findByPk(id);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Game not found',
|
||||
});
|
||||
}
|
||||
|
||||
await game.destroy();
|
||||
|
||||
// Clear cache
|
||||
await cacheUtils.deletePattern('games:*');
|
||||
await cacheUtils.deletePattern(`game:${id}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Game deleted successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment play count
|
||||
*/
|
||||
async incrementPlayCount(req, res, next) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const game = await Game.findByPk(id);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Game not found',
|
||||
});
|
||||
}
|
||||
|
||||
await game.increment('play_count');
|
||||
await game.reload();
|
||||
|
||||
// Clear cache
|
||||
await cacheUtils.deletePattern(`game:${id}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
id: game.id,
|
||||
play_count: game.play_count,
|
||||
},
|
||||
message: 'Play count incremented',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get games by type (for lesson matching)
|
||||
*/
|
||||
async getGamesByType(req, res, next) {
|
||||
try {
|
||||
const { type } = req.params;
|
||||
const { only_active = 'true' } = req.query;
|
||||
|
||||
const cacheKey = `games:type:${type}:${only_active}`;
|
||||
|
||||
const cached = await cacheUtils.get(cacheKey);
|
||||
if (cached) {
|
||||
return res.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
});
|
||||
}
|
||||
|
||||
const where = { type };
|
||||
if (only_active === 'true') where.is_active = true;
|
||||
|
||||
const games = await Game.findAll({
|
||||
where,
|
||||
order: [['display_order', 'ASC'], ['rating', 'DESC']],
|
||||
});
|
||||
|
||||
await cacheUtils.set(cacheKey, games, 3600);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: games,
|
||||
cached: false,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get game statistics
|
||||
*/
|
||||
async getGameStats(req, res, next) {
|
||||
try {
|
||||
const cacheKey = 'games:stats';
|
||||
|
||||
const cached = await cacheUtils.get(cacheKey);
|
||||
if (cached) {
|
||||
return res.json({
|
||||
success: true,
|
||||
data: cached,
|
||||
cached: true,
|
||||
});
|
||||
}
|
||||
|
||||
const [totalGames, activeGames, premiumGames, totalPlays] = await Promise.all([
|
||||
Game.count(),
|
||||
Game.count({ where: { is_active: true } }),
|
||||
Game.count({ where: { is_premium: true } }),
|
||||
Game.sum('play_count'),
|
||||
]);
|
||||
|
||||
const topGames = await Game.findAll({
|
||||
where: { is_active: true },
|
||||
order: [['play_count', 'DESC']],
|
||||
limit: 10,
|
||||
attributes: ['id', 'title', 'type', 'play_count', 'rating'],
|
||||
});
|
||||
|
||||
const stats = {
|
||||
totalGames,
|
||||
activeGames,
|
||||
premiumGames,
|
||||
totalPlays: totalPlays || 0,
|
||||
topGames,
|
||||
};
|
||||
|
||||
await cacheUtils.set(cacheKey, stats, 600);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: stats,
|
||||
cached: false,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new GameController();
|
||||
Reference in New Issue
Block a user