feat(users,professors): add promote student to professor and full student profile aggregation
This commit is contained in:
@@ -9,6 +9,12 @@ exports.create = catchAsync(async (req, res, next) => {
|
||||
return successResponse(res, 201, 'Professor created successfully', professor);
|
||||
});
|
||||
|
||||
exports.createFromUser = catchAsync(async (req, res, next) => {
|
||||
const userId = req.body.userId || req.params.userId || req.body.id;
|
||||
const result = await professorService.createProfessorFromUser(userId, req.body);
|
||||
return successResponse(res, 201, 'Professor created from user successfully', result);
|
||||
});
|
||||
|
||||
exports.getOne = catchAsync(async (req, res, next) => {
|
||||
const professor = await professorService.getProfessorById(req.params.id);
|
||||
return successResponse(res, 200, 'Professor retrieved successfully', professor);
|
||||
|
||||
@@ -12,6 +12,7 @@ const router = express.Router();
|
||||
router.use(authMiddleware);
|
||||
|
||||
router.post('/admin/create', perm.requires(PERMISSIONS.PROFESSORS_CREATE), validateCreateProfessor, professorController.create);
|
||||
router.post('/admin/create-from-user', perm.requires(PERMISSIONS.PROFESSORS_CREATE), professorController.createFromUser);
|
||||
router.get('/admin/get-all', perm.requires(PERMISSIONS.PROFESSORS_READ), professorController.getAll);
|
||||
router.get('/admin/search', perm.requires(PERMISSIONS.PROFESSORS_SEARCH), professorController.search);
|
||||
router.get('/admin/get-one/:id', perm.requires(PERMISSIONS.PROFESSORS_READ), professorController.getOne);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// /components/professors/professorService.js
|
||||
|
||||
const Professor = require('./professorModel');
|
||||
const User = require('../users/userModel');
|
||||
const Role = require('../roles/roleModel');
|
||||
const AppError = require('../../utils/AppError');
|
||||
const eventEmitter = require('../../events/eventEmitter');
|
||||
const EVENT_NAMES = require('../../constants/eventNames');
|
||||
@@ -43,6 +45,112 @@ const createProfessor = async (data) => {
|
||||
return professor;
|
||||
};
|
||||
|
||||
const createProfessorFromUser = async (userId, additionalData = {}) => {
|
||||
if (!userId) {
|
||||
throw new AppError('VALIDATION_FAILED', null, 'User ID is required');
|
||||
}
|
||||
|
||||
const user = await User.findById(userId);
|
||||
if (!user) {
|
||||
throw new AppError('USER_NOT_FOUND');
|
||||
}
|
||||
|
||||
const professorRole = await Role.findOne({ name: 'Professor' });
|
||||
if (!professorRole) {
|
||||
throw new AppError('DEFAULT_ROLE_NOT_FOUND', null, 'Professor role not found');
|
||||
}
|
||||
|
||||
// Update user role to Professor if not already
|
||||
if (String(user.role) !== String(professorRole._id)) {
|
||||
user.role = professorRole._id;
|
||||
await user.save();
|
||||
}
|
||||
|
||||
// Determine name and surname
|
||||
let firstName = String(additionalData.name || '').trim();
|
||||
let lastName = String(additionalData.surname || '').trim();
|
||||
|
||||
if (!firstName && !lastName) {
|
||||
const rawName = String(user.name || '').trim();
|
||||
const parts = rawName.split(/\s+/);
|
||||
if (parts.length > 1) {
|
||||
firstName = parts[0];
|
||||
lastName = parts.slice(1).join(' ');
|
||||
} else {
|
||||
firstName = rawName || 'استاد';
|
||||
lastName = rawName || 'استاد';
|
||||
}
|
||||
} else if (!lastName && firstName) {
|
||||
lastName = firstName;
|
||||
} else if (!firstName && lastName) {
|
||||
firstName = lastName;
|
||||
}
|
||||
|
||||
let nationalIdCode = String(additionalData.nationalIdCode || additionalData.nationalId || user.nationalIdCode || '').trim();
|
||||
const phoneNumber = String(additionalData.phoneNumber || additionalData.phone || user.phoneNumber || '').trim();
|
||||
|
||||
if (!nationalIdCode) {
|
||||
nationalIdCode = await allocatePlaceholderNationalId(phoneNumber);
|
||||
}
|
||||
|
||||
const email = additionalData.email ? String(additionalData.email).trim().toLowerCase() : (user.email ? String(user.email).trim().toLowerCase() : undefined);
|
||||
const cardNumber = additionalData.cardNumber ? String(additionalData.cardNumber).trim() : (user.cardNumber ? String(user.cardNumber).trim() : undefined);
|
||||
const shabaNumber = additionalData.shabaNumber || additionalData.iban ? String(additionalData.shabaNumber || additionalData.iban).trim() : (user.shabaNumber ? String(user.shabaNumber).trim() : undefined);
|
||||
const bio = additionalData.bio ? String(additionalData.bio).trim() : undefined;
|
||||
|
||||
let expertise = [];
|
||||
if (Array.isArray(additionalData.expertise)) {
|
||||
expertise = additionalData.expertise.map(String).map(s => s.trim()).filter(Boolean);
|
||||
} else if (typeof additionalData.expertise === 'string' && additionalData.expertise.trim()) {
|
||||
expertise = additionalData.expertise.split(',').map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
// Check if a Professor record already exists for this nationalIdCode or phoneNumber
|
||||
let professor = await Professor.findOne({
|
||||
$or: [
|
||||
{ nationalIdCode },
|
||||
{ phoneNumber }
|
||||
]
|
||||
});
|
||||
|
||||
if (professor) {
|
||||
professor.name = firstName;
|
||||
professor.surname = lastName;
|
||||
if (email) professor.email = email;
|
||||
if (cardNumber) professor.cardNumber = cardNumber;
|
||||
if (shabaNumber) professor.shabaNumber = shabaNumber;
|
||||
if (bio) professor.bio = bio;
|
||||
if (expertise.length > 0) professor.expertise = expertise;
|
||||
professor.isActive = true;
|
||||
await professor.save();
|
||||
} else {
|
||||
professor = await Professor.create({
|
||||
name: firstName,
|
||||
surname: lastName,
|
||||
nationalIdCode,
|
||||
phoneNumber,
|
||||
email,
|
||||
cardNumber,
|
||||
shabaNumber,
|
||||
bio,
|
||||
expertise,
|
||||
isActive: true
|
||||
});
|
||||
}
|
||||
|
||||
eventEmitter.emit(EVENT_NAMES.PROFESSOR_CREATED, {
|
||||
professorId: professor._id,
|
||||
name: `${professor.name} ${professor.surname}`
|
||||
});
|
||||
|
||||
const updatedUser = await User.findById(user._id)
|
||||
.select('-passwordHash -refreshTokens')
|
||||
.populate({ path: 'role', select: 'name permissions' })
|
||||
.lean();
|
||||
|
||||
return { professor, user: updatedUser };
|
||||
};
|
||||
|
||||
const getProfessorById = async (id) => {
|
||||
const professor = await Professor.findById(id).populate('courses', 'title type price');
|
||||
if (!professor) {
|
||||
@@ -117,6 +225,7 @@ const searchProfessors = async (queryParams) => {
|
||||
|
||||
module.exports = {
|
||||
createProfessor,
|
||||
createProfessorFromUser,
|
||||
getProfessorById,
|
||||
getAllProfessors,
|
||||
updateProfessor,
|
||||
|
||||
Reference in New Issue
Block a user