@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.
@@ -7,6 +7,7 @@ export declare enum ExperienceLevel {
7
7
  EXPERT = "EXPERT"
8
8
  }
9
9
  declare class Candidate extends EnduranceSchema {
10
+ entityId?: Types.ObjectId;
10
11
  contact: Types.ObjectId;
11
12
  experienceLevel: string;
12
13
  yearsOfExperience: number;
@@ -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
- const categories = test.categories.map(cat => ({ categoryId: cat.categoryId }));
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;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@programisto/edrm-exams",
4
- "version": "0.3.14",
4
+ "version": "0.3.16",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },