const { School } = require('../models'); const { cacheUtils } = require('../config/redis'); /** * School Controller - Quản lý thông tin trường học */ class SchoolController { /** * Get all schools with pagination and caching */ async getAllSchools(req, res, next) { try { const { page = 1, limit = 20, type, city, is_active } = req.query; const offset = (page - 1) * limit; // Generate cache key const cacheKey = `schools:list:${page}:${limit}:${type || 'all'}:${city || 'all'}:${is_active || 'all'}`; // Try to get from cache first const cached = await cacheUtils.get(cacheKey); if (cached) { return res.json({ success: true, data: cached, cached: true, }); } // Build query conditions const where = {}; if (type) where.school_type = type; if (city) where.city = city; if (is_active !== undefined) { where.is_active = is_active === 'true' || is_active === true; } // Query from database (through ProxySQL) const { count, rows } = await School.findAndCountAll({ where, limit: parseInt(limit), offset: parseInt(offset), order: [['school_name', 'ASC']], attributes: { exclude: ['config'] }, // Exclude sensitive data }); const result = { schools: rows, pagination: { total: count, page: parseInt(page), limit: parseInt(limit), totalPages: Math.ceil(count / limit), }, }; // Cache the result await cacheUtils.set(cacheKey, result, 3600); // Cache for 1 hour res.json({ success: true, data: result, cached: false, }); } catch (error) { next(error); } } /** * Get school by ID with caching */ async getSchoolById(req, res, next) { try { const { id } = req.params; const cacheKey = `school:${id}`; // Try cache first const cached = await cacheUtils.get(cacheKey); if (cached) { return res.json({ success: true, data: cached, cached: true, }); } // Query from database const school = await School.findByPk(id); if (!school) { return res.status(404).json({ success: false, message: 'School not found', }); } // Cache the result await cacheUtils.set(cacheKey, school, 7200); // Cache for 2 hours res.json({ success: true, data: school, cached: false, }); } catch (error) { next(error); } } /** * Create new school */ async createSchool(req, res, next) { try { const schoolData = req.body; // Validate required fields (you can use Joi for this) if (!schoolData.school_code || !schoolData.school_name || !schoolData.school_type) { return res.status(400).json({ success: false, message: 'Missing required fields', }); } const newSchool = await School.create(schoolData); await cacheUtils.deletePattern('schools:list:*'); res.status(201).json({ success: true, message: 'School created successfully', data: newSchool, }); } catch (error) { next(error); } } /** * Update school */ async updateSchool(req, res, next) { try { const { id } = req.params; const updateData = req.body; const school = await School.findByPk(id); if (!school) { return res.status(404).json({ success: false, message: 'School not found', }); } await school.update(updateData); // Invalidate cache await cacheUtils.delete(`school:${id}`); await cacheUtils.deletePattern('schools:list:*'); res.status(200).json({ success: true, message: 'School updated successfully', data: school, }); } catch (error) { next(error); } } /** * Delete school (soft delete) */ async deleteSchool(req, res, next) { try { const { id } = req.params; // Check if school exists const school = await School.findByPk(id); if (!school) { return res.status(404).json({ success: false, message: 'School not found', }); } // Soft delete - just mark as inactive await school.update({ is_active: false }); // Invalidate cache await cacheUtils.delete(`school:${id}`); await cacheUtils.deletePattern('schools:list:*'); res.status(200).json({ success: true, message: 'School deactivated successfully', data: school, }); } catch (error) { next(error); } } /** * Get school statistics */ async getSchoolStats(req, res, next) { try { const { id } = req.params; const cacheKey = `school:${id}:stats`; // Try cache first const cached = await cacheUtils.get(cacheKey); if (cached) { return res.json({ success: true, data: cached, cached: true, }); } // Get school with related data const school = await School.findByPk(id, { include: [ { association: 'classes', attributes: ['id'] }, { association: 'rooms', attributes: ['id'] }, ], }); if (!school) { return res.status(404).json({ success: false, message: 'School not found', }); } const stats = { school_id: id, school_name: school.school_name, total_classes: school.classes?.length || 0, total_rooms: school.rooms?.length || 0, capacity: school.capacity, }; // Cache for 30 minutes await cacheUtils.set(cacheKey, stats, 1800); res.json({ success: true, data: stats, cached: false, }); } catch (error) { next(error); } } /** * Get school datatypes */ async getSchoolDatatypes(req, res, next) { try { const datatypes = School.rawAttributes; res.json({ success: true, data: datatypes, }); } catch (error) { next(error); } } } module.exports = new SchoolController();