feat: add adminNotes and registered class counts for users
Expose nationalId aliases and enrollment counts on user list responses, and store admin notes on users, classes, and sessions.
This commit is contained in:
@@ -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];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user