275 lines
7.3 KiB
JavaScript
275 lines
7.3 KiB
JavaScript
const { TeacherDetail, UserProfile, UsersAuth } = require('../models');
|
|
const { cacheUtils } = require('../config/redis');
|
|
const { addDatabaseWriteJob } = require('../config/bullmq');
|
|
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 via BullMQ)
|
|
*/
|
|
async updateTeacher(req, res, next) {
|
|
try {
|
|
const { id } = req.params;
|
|
const updates = req.body;
|
|
|
|
const job = await addDatabaseWriteJob('update', 'TeacherDetail', {
|
|
id,
|
|
updates,
|
|
});
|
|
|
|
await cacheUtils.delete(`teacher:${id}`);
|
|
await cacheUtils.deletePattern('teachers:list:*');
|
|
|
|
res.status(202).json({
|
|
success: true,
|
|
message: 'Teacher update job queued',
|
|
jobId: job.id,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete teacher (update status to resigned)
|
|
*/
|
|
async deleteTeacher(req, res, next) {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
const job = await addDatabaseWriteJob('update', 'TeacherDetail', {
|
|
id,
|
|
updates: { status: 'resigned' },
|
|
});
|
|
|
|
await cacheUtils.delete(`teacher:${id}`);
|
|
await cacheUtils.deletePattern('teachers:list:*');
|
|
|
|
res.status(202).json({
|
|
success: true,
|
|
message: 'Teacher deletion job queued',
|
|
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();
|