@programisto/edrm-exams 0.3.14 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -20,6 +20,7 @@ export var ExperienceLevel;
|
|
|
20
20
|
})(ExperienceLevel || (ExperienceLevel = {}));
|
|
21
21
|
/* eslint-enable no-unused-vars */
|
|
22
22
|
let Candidate = class Candidate extends EnduranceSchema {
|
|
23
|
+
entityId;
|
|
23
24
|
contact;
|
|
24
25
|
experienceLevel;
|
|
25
26
|
yearsOfExperience;
|
|
@@ -32,6 +33,10 @@ let Candidate = class Candidate extends EnduranceSchema {
|
|
|
32
33
|
return CandidateModel;
|
|
33
34
|
}
|
|
34
35
|
};
|
|
36
|
+
__decorate([
|
|
37
|
+
EnduranceModelType.prop({ type: Types.ObjectId, ref: 'Entity', required: false }),
|
|
38
|
+
__metadata("design:type", Types.ObjectId)
|
|
39
|
+
], Candidate.prototype, "entityId", void 0);
|
|
35
40
|
__decorate([
|
|
36
41
|
EnduranceModelType.prop({ required: true, ref: 'Contact' }),
|
|
37
42
|
__metadata("design:type", Types.ObjectId)
|
|
@@ -8,6 +8,7 @@ import Candidate from '../models/candidate.model.js';
|
|
|
8
8
|
import ContactModel from '../models/contact.model.js';
|
|
9
9
|
import { generateLiveMessage } from '../lib/openai.js';
|
|
10
10
|
import { computeScoresByCategory } from '../lib/score-utils.js';
|
|
11
|
+
import { Types } from 'mongoose';
|
|
11
12
|
// Fonction utilitaire pour récupérer le nom du job
|
|
12
13
|
async function getJobName(targetJob) {
|
|
13
14
|
// Si c'est déjà une string (ancien format), on la retourne directement
|
|
@@ -1166,7 +1167,7 @@ class ExamsRouter extends EnduranceRouter {
|
|
|
1166
1167
|
*/
|
|
1167
1168
|
this.put('/test/addCustomQuestion/:id', authenticatedOptions, async (req, res) => {
|
|
1168
1169
|
const { id } = req.params;
|
|
1169
|
-
const { questionType, instruction, maxScore, time, categoryId } = req.body;
|
|
1170
|
+
const { questionType, instruction, maxScore, time, categoryId, possibleResponses, textType } = req.body;
|
|
1170
1171
|
try {
|
|
1171
1172
|
const test = await Test.findById(id);
|
|
1172
1173
|
if (!test) {
|
|
@@ -1186,7 +1187,9 @@ class ExamsRouter extends EnduranceRouter {
|
|
|
1186
1187
|
instruction,
|
|
1187
1188
|
maxScore,
|
|
1188
1189
|
time,
|
|
1189
|
-
...(categoryId != null && categoryId !== '' ? { categoryId } : {})
|
|
1190
|
+
...(categoryId != null && categoryId !== '' ? { categoryId } : {}),
|
|
1191
|
+
...(textType != null && textType !== '' ? { textType } : {}),
|
|
1192
|
+
...(questionType === 'MCQ' && Array.isArray(possibleResponses) ? { possibleResponses } : {})
|
|
1190
1193
|
});
|
|
1191
1194
|
await question.save();
|
|
1192
1195
|
test.questions.push({ questionId: question._id, order: test.questions.length });
|
|
@@ -1463,25 +1466,44 @@ class ExamsRouter extends EnduranceRouter {
|
|
|
1463
1466
|
if (!test) {
|
|
1464
1467
|
return res.status(404).json({ message: 'Test not found' });
|
|
1465
1468
|
}
|
|
1466
|
-
|
|
1467
|
-
const newResult = new TestResult({
|
|
1468
|
-
candidateId,
|
|
1469
|
-
testId,
|
|
1470
|
-
categories,
|
|
1471
|
-
state: 'pending',
|
|
1472
|
-
invitationDate: Date.now()
|
|
1473
|
-
});
|
|
1474
|
-
await newResult.save();
|
|
1475
|
-
// Récupérer l'email du candidat
|
|
1469
|
+
// Récupérer le candidat et le contact (avant de créer le TestResult pour pouvoir utiliser le candidat scopé entité)
|
|
1476
1470
|
const candidate = await Candidate.findById(candidateId);
|
|
1477
1471
|
if (!candidate) {
|
|
1478
1472
|
return res.status(404).json({ message: 'Candidate not found' });
|
|
1479
1473
|
}
|
|
1480
|
-
// Récupérer le contact pour obtenir l'email
|
|
1481
1474
|
const contact = await ContactModel.findById(candidate.contact);
|
|
1482
1475
|
if (!contact) {
|
|
1483
1476
|
return res.status(404).json({ message: 'Contact not found' });
|
|
1484
1477
|
}
|
|
1478
|
+
// Multi-entité : s'assurer qu'un Candidate existe pour l'entité courante (même contact).
|
|
1479
|
+
// Permet à un candidat déjà présent sur une autre entité de se connecter à l'espace candidat de cette entité.
|
|
1480
|
+
let entityCandidate = candidate;
|
|
1481
|
+
if (req.entity?._id) {
|
|
1482
|
+
const entityId = req.entity._id instanceof Types.ObjectId ? req.entity._id : new Types.ObjectId(String(req.entity._id));
|
|
1483
|
+
const existing = await Candidate.findOne({ contact: contact._id, entityId });
|
|
1484
|
+
if (!existing) {
|
|
1485
|
+
entityCandidate = new Candidate({
|
|
1486
|
+
contact: contact._id,
|
|
1487
|
+
entityId,
|
|
1488
|
+
skills: Array.isArray(candidate.skills) ? candidate.skills : [],
|
|
1489
|
+
experienceLevel: candidate.experienceLevel,
|
|
1490
|
+
yearsOfExperience: candidate.yearsOfExperience ?? 0
|
|
1491
|
+
});
|
|
1492
|
+
await entityCandidate.save();
|
|
1493
|
+
}
|
|
1494
|
+
else {
|
|
1495
|
+
entityCandidate = existing;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
const categories = test.categories.map((cat) => ({ categoryId: cat.categoryId }));
|
|
1499
|
+
const newResult = new TestResult({
|
|
1500
|
+
candidateId: entityCandidate._id,
|
|
1501
|
+
testId,
|
|
1502
|
+
categories,
|
|
1503
|
+
state: 'pending',
|
|
1504
|
+
invitationDate: Date.now()
|
|
1505
|
+
});
|
|
1506
|
+
await newResult.save();
|
|
1485
1507
|
const email = contact.email;
|
|
1486
1508
|
// Construire le lien d'invitation
|
|
1487
1509
|
const testLink = (process.env.TEST_INVITATION_LINK || '') + email;
|