|
|
|
@@ -3,6 +3,7 @@
|
|
|
|
|
|
|
|
|
|
const User = require('./userModel');
|
|
|
|
|
const Role = require('../roles/roleModel');
|
|
|
|
|
const Class = require('../classes/classModel');
|
|
|
|
|
const bcrypt = require('bcryptjs');
|
|
|
|
|
const AppError = require('../../utils/AppError');
|
|
|
|
|
const { calculateMeta } = require('../../utils/pagination');
|
|
|
|
@@ -11,6 +12,29 @@ const { sendAccountCreatedSms } = require('../../utils/senders/smsMessages');
|
|
|
|
|
const logger = require('../../utils/logger');
|
|
|
|
|
const { mergeFullName, normalizeGender } = require('../../utils/userProfile');
|
|
|
|
|
|
|
|
|
|
const normalizeAdminNotes = (value) => {
|
|
|
|
|
if (value == null) return undefined;
|
|
|
|
|
if (!Array.isArray(value)) return undefined;
|
|
|
|
|
return value.map((n) => String(n).trim()).filter(Boolean);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const withUserListExtras = async (users) => {
|
|
|
|
|
if (!users.length) return users;
|
|
|
|
|
const userIds = users.map((u) => u._id);
|
|
|
|
|
const counts = await Class.aggregate([
|
|
|
|
|
{ $match: { students: { $in: userIds } } },
|
|
|
|
|
{ $unwind: '$students' },
|
|
|
|
|
{ $match: { students: { $in: userIds } } },
|
|
|
|
|
{ $group: { _id: '$students', count: { $sum: 1 } } }
|
|
|
|
|
]);
|
|
|
|
|
const countMap = Object.fromEntries(counts.map((c) => [String(c._id), c.count]));
|
|
|
|
|
return users.map((u) => ({
|
|
|
|
|
...u,
|
|
|
|
|
nationalId: u.nationalIdCode,
|
|
|
|
|
registeredClassesCount: countMap[String(u._id)] || 0
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const POPULATE_ROLE = { path: 'role', select: 'name permissions' };
|
|
|
|
|
const SAFE_FIELDS = '-passwordHash -refreshTokens';
|
|
|
|
|
const ALLOWED_MESSENGERS = ['Bale', 'WhatsApp', 'Telegram', 'SMS', 'Email'];
|
|
|
|
@@ -54,7 +78,8 @@ const pickProfileFields = (body = {}) => {
|
|
|
|
|
birthDate: body.birthDate || undefined,
|
|
|
|
|
education: body.education,
|
|
|
|
|
parentPhoneNumber: body.parentPhoneNumber,
|
|
|
|
|
preferredMessenger: normalizePreferredMessengers(body.preferredMessenger)
|
|
|
|
|
preferredMessenger: normalizePreferredMessengers(body.preferredMessenger),
|
|
|
|
|
adminNotes: normalizeAdminNotes(body.adminNotes)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Object.keys(fields).forEach((key) => {
|
|
|
|
@@ -87,7 +112,8 @@ const signUp = async (body) => {
|
|
|
|
|
const getUserById = async (id) => {
|
|
|
|
|
const user = await User.findById(id).select(SAFE_FIELDS).populate(POPULATE_ROLE).lean();
|
|
|
|
|
if (!user) throw new AppError('USER_NOT_FOUND');
|
|
|
|
|
return user;
|
|
|
|
|
const [enriched] = await withUserListExtras([user]);
|
|
|
|
|
return enriched;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getAllUsers = async (query) => {
|
|
|
|
@@ -111,7 +137,7 @@ const getAllUsers = async (query) => {
|
|
|
|
|
User.countDocuments(filter)
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return { data: items, meta: calculateMeta(total, page, limit) };
|
|
|
|
|
return { data: await withUserListExtras(items), meta: calculateMeta(total, page, limit) };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const searchUsers = async (query) => getAllUsers(query);
|
|
|
|
@@ -204,6 +230,9 @@ const updateUser = async (id, body) => {
|
|
|
|
|
if (preferredMessenger !== undefined) {
|
|
|
|
|
update.preferredMessenger = normalizePreferredMessengers(preferredMessenger) || [];
|
|
|
|
|
}
|
|
|
|
|
if (body.adminNotes !== undefined) {
|
|
|
|
|
update.adminNotes = normalizeAdminNotes(body.adminNotes) || [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof username === 'string' && username.trim()) {
|
|
|
|
|
update.username = username.trim();
|
|
|
|
@@ -213,7 +242,7 @@ const updateUser = async (id, body) => {
|
|
|
|
|
delete update.surname;
|
|
|
|
|
|
|
|
|
|
Object.keys(update).forEach((key) => {
|
|
|
|
|
if (key === 'preferredMessenger') return;
|
|
|
|
|
if (key === 'preferredMessenger' || key === 'adminNotes') return;
|
|
|
|
|
if (update[key] === '' || update[key] === null || update[key] === undefined) {
|
|
|
|
|
delete update[key];
|
|
|
|
|
}
|
|
|
|
|