@programisto/edrm-exams 0.3.12 → 0.3.13
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.
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { enduranceListener, enduranceEmitter, enduranceEventTypes } from '@programisto/endurance';
|
|
2
|
+
import Test from '../models/test.model.js';
|
|
3
|
+
import TestResult from '../models/test-result.model.js';
|
|
4
|
+
import Candidate from '../models/candidate.model.js';
|
|
5
|
+
import ContactModel from '../models/contact.model.js';
|
|
6
|
+
const EVENT_INVITE_TO_TECHNICAL_TEST = 'INVITE_TO_TECHNICAL_TEST';
|
|
7
|
+
/**
|
|
8
|
+
* Même logique que POST /exams/invite : crée un TestResult et envoie l'email d'invitation.
|
|
9
|
+
* Déclenché quand une candidature est créée sur une offre avec un test lié (internal-portal).
|
|
10
|
+
*/
|
|
11
|
+
async function inviteCandidateToTest(payload) {
|
|
12
|
+
const candidateId = typeof payload.candidateId === 'object' && payload.candidateId?.toString
|
|
13
|
+
? payload.candidateId.toString()
|
|
14
|
+
: String(payload.candidateId ?? '');
|
|
15
|
+
const testId = typeof payload.testId === 'object' && payload.testId?.toString
|
|
16
|
+
? payload.testId.toString()
|
|
17
|
+
: String(payload.testId ?? '');
|
|
18
|
+
if (!candidateId || !testId)
|
|
19
|
+
return;
|
|
20
|
+
const existing = await TestResult.findOne({ candidateId, testId });
|
|
21
|
+
if (existing) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const test = await Test.findById(testId);
|
|
25
|
+
if (!test) {
|
|
26
|
+
console.warn('[INVITE_TO_TECHNICAL_TEST] Test not found:', testId);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const categories = test.categories?.map((cat) => ({ categoryId: cat.categoryId })) ?? [];
|
|
30
|
+
const newResult = new TestResult({
|
|
31
|
+
candidateId,
|
|
32
|
+
testId,
|
|
33
|
+
categories,
|
|
34
|
+
state: 'pending',
|
|
35
|
+
invitationDate: Date.now()
|
|
36
|
+
});
|
|
37
|
+
await newResult.save();
|
|
38
|
+
const candidate = await Candidate.findById(candidateId);
|
|
39
|
+
if (!candidate) {
|
|
40
|
+
console.warn('[INVITE_TO_TECHNICAL_TEST] Candidate not found:', candidateId);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const contact = await ContactModel.findById(candidate.contact);
|
|
44
|
+
if (!contact) {
|
|
45
|
+
console.warn('[INVITE_TO_TECHNICAL_TEST] Contact not found for candidate:', candidateId);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const email = contact.email;
|
|
49
|
+
if (!email) {
|
|
50
|
+
console.warn('[INVITE_TO_TECHNICAL_TEST] No email for contact');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const testLink = (process.env.TEST_INVITATION_LINK || '') + email;
|
|
54
|
+
const emailUser = process.env.EMAIL_USER;
|
|
55
|
+
const emailPassword = process.env.EMAIL_PASSWORD;
|
|
56
|
+
await enduranceEmitter.emit(enduranceEventTypes.SEND_EMAIL, {
|
|
57
|
+
template: 'test-invitation',
|
|
58
|
+
to: email,
|
|
59
|
+
from: emailUser,
|
|
60
|
+
emailUser,
|
|
61
|
+
emailPassword,
|
|
62
|
+
data: {
|
|
63
|
+
firstname: contact.firstname,
|
|
64
|
+
testName: test?.title || '',
|
|
65
|
+
testLink
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
enduranceListener.createListener(EVENT_INVITE_TO_TECHNICAL_TEST, async (args) => {
|
|
70
|
+
try {
|
|
71
|
+
if (typeof args === 'object' && args !== null) {
|
|
72
|
+
await inviteCandidateToTest(args);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error('[INVITE_TO_TECHNICAL_TEST] Error inviting candidate to test:', err);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
export default enduranceListener;
|