const { TeacherDetail, UserProfile, UsersAuth } = require('../models'); const { cacheUtils } = require('../config/redis'); const teacherProfileService = require('../services/teacherProfileService'); /** * Teacher Controller - Quản lý giáo viên */ class TeacherController { /** * Get all teachers with pagination and caching */ async getAllTeachers(req, res, next) { try { const { page = 1, limit = 20, status, teacher_type, school_id } = req.query; const offset = (page - 1) * limit; const cacheKey = `teachers:list:${page}:${limit}:${status || 'all'}:${teacher_type || 'all'}:${school_id || 'all'}`; const cached = await cacheUtils.get(cacheKey); if (cached) { return res.json({ success: true, data: cached, cached: true, }); } const where = {}; if (status) where.status = status; if (teacher_type) where.teacher_type = teacher_type; // Query teachers const { count, rows } = await TeacherDetail.findAndCountAll({ where, limit: parseInt(limit), offset: parseInt(offset), order: [['created_at', 'DESC']], }); // Manually fetch profiles for each teacher const teachersWithProfiles = await Promise.all( rows.map(async (teacher) => { const profile = await UserProfile.findOne({ where: { user_id: teacher.user_id }, attributes: ['id', 'full_name', 'phone', 'date_of_birth', 'gender', 'address', 'school_id', 'city', 'district', 'avatar_url'], }); // Filter by school_id if provided if (school_id && (!profile || profile.school_id !== school_id)) { return null; } return { ...teacher.toJSON(), profile: profile ? profile.toJSON() : null, }; }) ); // Filter out nulls (teachers not matching school_id) const filteredTeachers = teachersWithProfiles.filter(t => t !== null); const result = { teachers: filteredTeachers, pagination: { total: school_id ? filteredTeachers.length : count, page: parseInt(page), limit: parseInt(limit), totalPages: Math.ceil((school_id ? filteredTeachers.length : count) / limit), }, }; await cacheUtils.set(cacheKey, result, 1800); res.json({ success: true, data: result, cached: false, }); } catch (error) { next(error); } } /** * Get teacher by ID with manual profile fetch */ async getTeacherById(req, res, next) { try { const { id } = req.params; const cacheKey = `teacher:${id}`; const cached = await cacheUtils.get(cacheKey); if (cached) { return res.json({ success: true, data: cached, cached: true, }); } const teacher = await TeacherDetail.findByPk(id); if (!teacher) { return res.status(404).json({ success: false, message: 'Teacher not found', }); } // Manually fetch profile const profile = await UserProfile.findOne({ where: { user_id: teacher.user_id }, }); const teacherData = { ...teacher.toJSON(), profile: profile ? profile.toJSON() : null, }; await cacheUtils.set(cacheKey, teacherData, 3600); res.json({ success: true, data: teacherData, cached: false, }); } catch (error) { next(error); } } /** * Create new teacher with full profile (users_auth + user_profile + teacher_detail) */ async createTeacher(req, res, next) { try { const teacherData = req.body; // Use service to create full teacher profile const result = await teacherProfileService.createTeacherWithProfile(teacherData); // Clear cache await cacheUtils.deletePattern('teachers:list:*'); res.status(201).json({ success: true, message: 'Teacher created successfully', data: { user_id: result.user_id, username: result.username, email: result.email, temporary_password: result.temporary_password, // null if user provided password teacher_code: result.teacher_detail.teacher_code, teacher_type: result.teacher_detail.teacher_type, profile: { full_name: result.profile.full_name, needs_update: result.profile.etc?.needs_profile_update || false, } }, }); } catch (error) { next(error); } } /** * Update teacher profile (cho phép user tự cập nhật) */ async updateTeacherProfile(req, res, next) { try { const { id } = req.params; // user_id or teacher_id const profileData = req.body; // Nếu id là teacher_id, tìm user_id let userId = id; if (profileData.teacher_id) { const teacher = await TeacherDetail.findByPk(profileData.teacher_id); if (!teacher) { return res.status(404).json({ success: false, message: 'Teacher not found', }); } userId = teacher.user_id; } // Update profile const updatedProfile = await teacherProfileService.updateTeacherProfile(userId, profileData); // Clear cache await cacheUtils.delete(`teacher:${id}`); await cacheUtils.delete(`user:profile:${userId}`); await cacheUtils.deletePattern('teachers:list:*'); res.json({ success: true, message: 'Teacher profile updated successfully', data: updatedProfile, }); } catch (error) { next(error); } } /** * Update teacher */ async updateTeacher(req, res, next) { try { const { id } = req.params; const updates = req.body; const teacher = await TeacherDetail.findByPk(id); if (!teacher) { return res.status(404).json({ success: false, message: 'Teacher not found', }); } await teacher.update(updates); await cacheUtils.delete(`teacher:${id}`); await cacheUtils.deletePattern('teachers:list:*'); res.status(200).json({ success: true, message: 'Teacher updated successfully', data: teacher, }); } catch (error) { next(error); } } /** * Delete teacher (update status to resigned) */ async deleteTeacher(req, res, next) { try { const { id } = req.params; const teacher = await TeacherDetail.findByPk(id); if (!teacher) { return res.status(404).json({ success: false, message: 'Teacher not found', }); } await teacher.update({ status: 'resigned' }); await cacheUtils.delete(`teacher:${id}`); await cacheUtils.deletePattern('teachers:list:*'); res.status(200).json({ success: true, message: 'Teacher status updated to resigned', data: teacher, }); } catch (error) { next(error); } } jobId: job.id, }); } catch (error) { next(error); } } /** * Get teacher datatypes */ async getTeacherDatatypes(req, res, next) { try { const datatypes = TeacherDetail.rawAttributes; res.json({ success: true, data: datatypes, }); } catch (error) { next(error); } } } module.exports = new TeacherController();