@programisto/edrm-exams 0.1.4 → 0.1.5
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.
- package/README.md +135 -0
- package/dist/bin/www.d.ts +2 -0
- package/dist/bin/www.js +9 -0
- package/dist/modules/edrm-exams/lib/openai/correctQuestion.txt +10 -0
- package/dist/modules/edrm-exams/lib/openai/createQuestion.txt +68 -0
- package/dist/modules/edrm-exams/lib/openai.d.ts +36 -0
- package/dist/modules/edrm-exams/lib/openai.js +82 -0
- package/dist/modules/edrm-exams/listeners/correct.listener.d.ts +2 -0
- package/dist/modules/edrm-exams/listeners/correct.listener.js +85 -0
- package/dist/modules/edrm-exams/models/candidate.models.d.ts +13 -0
- package/dist/modules/edrm-exams/models/candidate.models.js +59 -0
- package/dist/modules/edrm-exams/models/company.model.d.ts +8 -0
- package/dist/modules/edrm-exams/models/company.model.js +34 -0
- package/dist/modules/edrm-exams/models/test-category.models.d.ts +7 -0
- package/dist/modules/edrm-exams/models/test-category.models.js +29 -0
- package/dist/modules/edrm-exams/models/test-question.model.d.ts +25 -0
- package/dist/modules/edrm-exams/models/test-question.model.js +70 -0
- package/dist/modules/edrm-exams/models/test-result.model.d.ts +26 -0
- package/dist/modules/edrm-exams/models/test-result.model.js +70 -0
- package/dist/modules/edrm-exams/models/test.model.d.ts +52 -0
- package/dist/modules/edrm-exams/models/test.model.js +123 -0
- package/dist/modules/edrm-exams/models/user.model.d.ts +18 -0
- package/dist/modules/edrm-exams/models/user.model.js +64 -0
- package/dist/modules/edrm-exams/routes/company.router.d.ts +7 -0
- package/dist/modules/edrm-exams/routes/company.router.js +108 -0
- package/dist/modules/edrm-exams/routes/exams-candidate.router.d.ts +7 -0
- package/dist/modules/edrm-exams/routes/exams-candidate.router.js +299 -0
- package/dist/modules/edrm-exams/routes/exams.router.d.ts +7 -0
- package/dist/modules/edrm-exams/routes/exams.router.js +1012 -0
- package/dist/modules/edrm-exams/routes/result.router.d.ts +7 -0
- package/dist/modules/edrm-exams/routes/result.router.js +314 -0
- package/dist/modules/edrm-exams/routes/user.router.d.ts +7 -0
- package/dist/modules/edrm-exams/routes/user.router.js +96 -0
- package/package.json +73 -8
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { EnduranceRouter, EnduranceAuthMiddleware, enduranceEmitter, enduranceEventTypes } from 'endurance-core';
|
|
2
|
+
import CandidateModel from '../models/candidate.models.js';
|
|
3
|
+
import TestResult, { TestState } from '../models/test-result.model.js';
|
|
4
|
+
import Test from '../models/test.model.js';
|
|
5
|
+
class ResultRouter extends EnduranceRouter {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(EnduranceAuthMiddleware.getInstance());
|
|
8
|
+
}
|
|
9
|
+
setupRoutes() {
|
|
10
|
+
const authenticatedOptions = {
|
|
11
|
+
requireAuth: false,
|
|
12
|
+
permissions: []
|
|
13
|
+
};
|
|
14
|
+
// Lister tous les résultats de tests d'un candidat
|
|
15
|
+
this.get('/results/:candidateId', authenticatedOptions, async (req, res) => {
|
|
16
|
+
try {
|
|
17
|
+
const { candidateId } = req.params;
|
|
18
|
+
const page = parseInt(req.query.page) || 1;
|
|
19
|
+
const limit = parseInt(req.query.limit) || 10;
|
|
20
|
+
const skip = (page - 1) * limit;
|
|
21
|
+
const state = req.query.state || 'all';
|
|
22
|
+
const sortBy = req.query.sortBy || 'invitationDate';
|
|
23
|
+
const sortOrder = req.query.sortOrder || 'desc';
|
|
24
|
+
// Vérifier si le candidat existe
|
|
25
|
+
const candidate = await CandidateModel.findById(candidateId);
|
|
26
|
+
if (!candidate) {
|
|
27
|
+
return res.status(404).json({ message: 'Candidat non trouvé' });
|
|
28
|
+
}
|
|
29
|
+
// Construction de la requête
|
|
30
|
+
const query = { candidateId };
|
|
31
|
+
if (state !== 'all') {
|
|
32
|
+
query.state = state;
|
|
33
|
+
}
|
|
34
|
+
// Construction du tri
|
|
35
|
+
const allowedSortFields = ['invitationDate', 'state', 'score'];
|
|
36
|
+
const sortField = allowedSortFields.includes(sortBy) ? sortBy : 'invitationDate';
|
|
37
|
+
const sortOptions = {
|
|
38
|
+
[sortField]: sortOrder === 'asc' ? 1 : -1
|
|
39
|
+
};
|
|
40
|
+
const [results, total] = await Promise.all([
|
|
41
|
+
TestResult.find(query)
|
|
42
|
+
.sort(sortOptions)
|
|
43
|
+
.skip(skip)
|
|
44
|
+
.limit(limit)
|
|
45
|
+
.lean()
|
|
46
|
+
.exec(),
|
|
47
|
+
TestResult.countDocuments(query)
|
|
48
|
+
]);
|
|
49
|
+
// Récupérer les informations des tests associés
|
|
50
|
+
const testIds = results.map(result => result.testId);
|
|
51
|
+
const tests = await Test.find({ _id: { $in: testIds } }).lean();
|
|
52
|
+
const testsMap = new Map(tests.map(test => [test._id.toString(), test]));
|
|
53
|
+
// Récupérer tous les IDs de catégories utilisés dans les tests
|
|
54
|
+
const allCategoryIds = Array.from(new Set(tests.flatMap(test => (test.categories || []).map((cat) => cat.categoryId?.toString()))));
|
|
55
|
+
const TestCategory = (await import('../models/test-category.models.js')).default;
|
|
56
|
+
const categoriesDocs = await TestCategory.find({ _id: { $in: allCategoryIds } }).lean();
|
|
57
|
+
const categoriesMap = new Map(categoriesDocs.map(cat => [cat._id.toString(), cat.name]));
|
|
58
|
+
// Combiner les résultats avec les informations des tests et des catégories
|
|
59
|
+
const TestQuestion = (await import('../models/test-question.model.js')).default;
|
|
60
|
+
const resultsWithTests = await Promise.all(results.map(async (result) => {
|
|
61
|
+
const test = testsMap.get(result.testId.toString());
|
|
62
|
+
let categoriesWithNames = [];
|
|
63
|
+
let maxScore = 0;
|
|
64
|
+
if (test && test.categories) {
|
|
65
|
+
categoriesWithNames = test.categories.map((cat) => ({
|
|
66
|
+
...cat,
|
|
67
|
+
categoryName: categoriesMap.get(cat.categoryId?.toString()) || 'Catégorie inconnue'
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
if (test && test.questions && test.questions.length > 0) {
|
|
71
|
+
const questionIds = test.questions.map((q) => q.questionId || q);
|
|
72
|
+
const questions = await TestQuestion.find({ _id: { $in: questionIds } }).lean();
|
|
73
|
+
maxScore = questions.reduce((sum, q) => sum + (q.maxScore || 0), 0);
|
|
74
|
+
}
|
|
75
|
+
const { responses, ...resultWithoutResponses } = result;
|
|
76
|
+
return {
|
|
77
|
+
...resultWithoutResponses,
|
|
78
|
+
testResultId: result._id,
|
|
79
|
+
maxScore,
|
|
80
|
+
test: test
|
|
81
|
+
? {
|
|
82
|
+
title: test.title,
|
|
83
|
+
description: test.description,
|
|
84
|
+
targetJob: test.targetJob,
|
|
85
|
+
seniorityLevel: test.seniorityLevel,
|
|
86
|
+
categories: categoriesWithNames
|
|
87
|
+
}
|
|
88
|
+
: null
|
|
89
|
+
};
|
|
90
|
+
}));
|
|
91
|
+
const totalPages = Math.ceil(total / limit);
|
|
92
|
+
return res.json({
|
|
93
|
+
data: resultsWithTests,
|
|
94
|
+
pagination: {
|
|
95
|
+
currentPage: page,
|
|
96
|
+
totalPages,
|
|
97
|
+
totalItems: total,
|
|
98
|
+
itemsPerPage: limit,
|
|
99
|
+
hasNextPage: page < totalPages,
|
|
100
|
+
hasPreviousPage: page > 1
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
console.error('Erreur lors de la récupération des résultats :', err);
|
|
106
|
+
res.status(500).json({ message: 'Erreur interne du serveur' });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
// Obtenir les infos de base d'un test (sans les questions), avec categoryName et maxTime
|
|
110
|
+
this.get('/test/:id', authenticatedOptions, async (req, res) => {
|
|
111
|
+
try {
|
|
112
|
+
const { id } = req.params;
|
|
113
|
+
const TestCategory = (await import('../models/test-category.models.js')).default;
|
|
114
|
+
const TestQuestion = (await import('../models/test-question.model.js')).default;
|
|
115
|
+
// Récupérer le test sans les questions
|
|
116
|
+
const test = await Test.findById(id).lean();
|
|
117
|
+
if (!test) {
|
|
118
|
+
return res.status(404).json({ message: 'Test non trouvé' });
|
|
119
|
+
}
|
|
120
|
+
// Récupérer les noms des catégories
|
|
121
|
+
const categoryIds = (test.categories || []).map((cat) => cat.categoryId?.toString());
|
|
122
|
+
const categoriesDocs = await TestCategory.find({ _id: { $in: categoryIds } }).lean();
|
|
123
|
+
const categoriesMap = new Map(categoriesDocs.map(cat => [cat._id.toString(), cat.name]));
|
|
124
|
+
const categoriesWithNames = (test.categories || []).map((cat) => ({
|
|
125
|
+
...cat,
|
|
126
|
+
categoryName: categoriesMap.get(cat.categoryId?.toString()) || 'Catégorie inconnue'
|
|
127
|
+
}));
|
|
128
|
+
// Calculer la somme du temps de toutes les questions
|
|
129
|
+
const questions = await TestQuestion.find({ _id: { $in: (test.questions || []).map((q) => q.questionId) } }).lean();
|
|
130
|
+
const maxTime = questions.reduce((sum, q) => sum + (q.time || 0), 0);
|
|
131
|
+
// Construire la réponse sans les questions
|
|
132
|
+
const { questions: _questions, // on retire les questions
|
|
133
|
+
...testWithoutQuestions } = test;
|
|
134
|
+
return res.json({
|
|
135
|
+
...testWithoutQuestions,
|
|
136
|
+
categories: categoriesWithNames,
|
|
137
|
+
maxTime
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
console.error('Erreur lors de la récupération du test :', err);
|
|
142
|
+
res.status(500).json({ message: 'Erreur interne du serveur' });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
// Obtenir l'ID de la prochaine question non répondue pour un résultat de test
|
|
146
|
+
this.get('/:id/nextQuestion', authenticatedOptions, async (req, res) => {
|
|
147
|
+
try {
|
|
148
|
+
const { id } = req.params;
|
|
149
|
+
const { currentQuestionId } = req.query;
|
|
150
|
+
// Récupérer le résultat de test
|
|
151
|
+
const result = await TestResult.findById(id);
|
|
152
|
+
if (!result) {
|
|
153
|
+
return res.status(404).json({ message: 'Résultat non trouvé' });
|
|
154
|
+
}
|
|
155
|
+
// Récupérer le test associé
|
|
156
|
+
const test = await Test.findById(result.testId).lean();
|
|
157
|
+
if (!test) {
|
|
158
|
+
return res.status(404).json({ message: 'Test non trouvé' });
|
|
159
|
+
}
|
|
160
|
+
// Liste des questions du test dans l'ordre
|
|
161
|
+
const questions = test.questions || [];
|
|
162
|
+
if (currentQuestionId) {
|
|
163
|
+
// Si on a un currentQuestionId, on cherche la question suivante dans l'ordre
|
|
164
|
+
const currentIndex = questions.findIndex(q => (q.questionId ? q.questionId.toString() : q.toString()) === currentQuestionId);
|
|
165
|
+
if (currentIndex === -1) {
|
|
166
|
+
return res.status(404).json({ message: 'Question courante non trouvée' });
|
|
167
|
+
}
|
|
168
|
+
// Si c'est la dernière question
|
|
169
|
+
if (currentIndex === questions.length - 1) {
|
|
170
|
+
// On est sur la dernière réponse, on met à jour la date de fin
|
|
171
|
+
result.endTime = new Date();
|
|
172
|
+
await result.save();
|
|
173
|
+
return res.json({ nextQuestionId: 'result' });
|
|
174
|
+
}
|
|
175
|
+
// Retourner la question suivante
|
|
176
|
+
const nextQuestion = questions[currentIndex + 1];
|
|
177
|
+
// Si c'est la première question (currentIndex === -1 avant), on met à jour la date de début
|
|
178
|
+
if (currentIndex === 0 && !result.startTime) {
|
|
179
|
+
result.startTime = new Date();
|
|
180
|
+
await result.save();
|
|
181
|
+
}
|
|
182
|
+
return res.json({
|
|
183
|
+
nextQuestionId: nextQuestion.questionId
|
|
184
|
+
? nextQuestion.questionId.toString()
|
|
185
|
+
: nextQuestion.toString()
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// Comportement original : chercher la première question non répondue
|
|
190
|
+
const answeredIds = (result.responses || []).map((r) => r.questionId.toString());
|
|
191
|
+
let nextQuestionId = null;
|
|
192
|
+
for (const q of questions) {
|
|
193
|
+
const qid = (q.questionId ? q.questionId.toString() : q.toString());
|
|
194
|
+
if (!answeredIds.includes(qid)) {
|
|
195
|
+
nextQuestionId = qid;
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!nextQuestionId) {
|
|
200
|
+
// Plus de question à répondre, on met à jour la date de fin
|
|
201
|
+
result.endTime = new Date();
|
|
202
|
+
await result.save();
|
|
203
|
+
nextQuestionId = 'result';
|
|
204
|
+
}
|
|
205
|
+
else if (questions.length > 0 && nextQuestionId === (questions[0].questionId ? questions[0].questionId.toString() : questions[0].toString()) && !result.startTime) {
|
|
206
|
+
// Si c'est la première question, on met à jour la date de début
|
|
207
|
+
result.startTime = new Date();
|
|
208
|
+
await result.save();
|
|
209
|
+
}
|
|
210
|
+
return res.json({ nextQuestionId });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
console.error('Erreur lors de la récupération de la prochaine question :', err);
|
|
215
|
+
res.status(500).json({ message: 'Erreur interne du serveur' });
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
// Afficher une question par son ID (optionnellement vérifier la session)
|
|
219
|
+
this.get('/question/:idQuestion', authenticatedOptions, async (req, res) => {
|
|
220
|
+
try {
|
|
221
|
+
const { idQuestion } = req.params;
|
|
222
|
+
const { sessionId } = req.query;
|
|
223
|
+
const TestQuestion = (await import('../models/test-question.model.js')).default;
|
|
224
|
+
// Récupérer la question
|
|
225
|
+
const question = await TestQuestion.findById(idQuestion).lean();
|
|
226
|
+
if (!question) {
|
|
227
|
+
return res.status(404).json({ message: 'Question non trouvée' });
|
|
228
|
+
}
|
|
229
|
+
// Optionnel : vérifier que la question appartient bien au test de la session et n'a pas déjà été répondue
|
|
230
|
+
if (sessionId) {
|
|
231
|
+
const result = await TestResult.findById(sessionId).lean();
|
|
232
|
+
if (!result) {
|
|
233
|
+
return res.status(404).json({ message: 'Session (résultat) non trouvée' });
|
|
234
|
+
}
|
|
235
|
+
const test = await Test.findById(result.testId).lean();
|
|
236
|
+
if (!test) {
|
|
237
|
+
return res.status(404).json({ message: 'Test non trouvé' });
|
|
238
|
+
}
|
|
239
|
+
const questionIds = (test.questions || []).map((q) => q.questionId?.toString());
|
|
240
|
+
if (!questionIds.includes(idQuestion)) {
|
|
241
|
+
return res.status(403).json({ message: 'Question non autorisée pour cette session' });
|
|
242
|
+
}
|
|
243
|
+
// Vérifier que la question n'a pas déjà été répondue
|
|
244
|
+
const alreadyAnswered = (result.responses || []).some((r) => r.questionId?.toString() === idQuestion);
|
|
245
|
+
if (alreadyAnswered) {
|
|
246
|
+
return res.status(403).json({ message: 'Question déjà répondue pour cette session' });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return res.json({ question });
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
console.error('Erreur lors de la récupération de la question :', err);
|
|
253
|
+
res.status(500).json({ message: 'Erreur interne du serveur' });
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
// Enregistrer la réponse à une question pour un résultat de test
|
|
257
|
+
this.post('/response', authenticatedOptions, async (req, res) => {
|
|
258
|
+
try {
|
|
259
|
+
const { response, questionId, testResultId } = req.body;
|
|
260
|
+
// Récupérer le résultat de test
|
|
261
|
+
const result = await TestResult.findById(testResultId);
|
|
262
|
+
if (!result) {
|
|
263
|
+
return res.status(404).json({ message: 'Résultat non trouvé' });
|
|
264
|
+
}
|
|
265
|
+
// Récupérer le test associé
|
|
266
|
+
const test = await Test.findById(result.testId);
|
|
267
|
+
if (!test) {
|
|
268
|
+
return res.status(404).json({ message: 'Test non trouvé' });
|
|
269
|
+
}
|
|
270
|
+
// Vérifier que la question appartient bien au test
|
|
271
|
+
const questionIds = (test.questions || []).map((q) => q.questionId?.toString());
|
|
272
|
+
if (!questionIds.includes(questionId)) {
|
|
273
|
+
return res.status(403).json({ message: 'Question non autorisée pour ce test' });
|
|
274
|
+
}
|
|
275
|
+
// Vérifier que la question n'a pas déjà été répondue
|
|
276
|
+
const alreadyAnswered = (result.responses || []).some((r) => r.questionId?.toString() === questionId);
|
|
277
|
+
if (alreadyAnswered) {
|
|
278
|
+
return res.status(403).json({ message: 'Question déjà répondue pour cette session' });
|
|
279
|
+
}
|
|
280
|
+
// Enregistrer la réponse
|
|
281
|
+
result.responses = result.responses || [];
|
|
282
|
+
result.responses.push({
|
|
283
|
+
questionId,
|
|
284
|
+
response,
|
|
285
|
+
score: 0,
|
|
286
|
+
comment: ''
|
|
287
|
+
});
|
|
288
|
+
// Vérifier si c'était la dernière question
|
|
289
|
+
const totalQuestions = test.questions.length;
|
|
290
|
+
const answeredQuestions = result.responses.length;
|
|
291
|
+
if (answeredQuestions === totalQuestions) {
|
|
292
|
+
result.state = TestState.Finish;
|
|
293
|
+
// Déclencher la correction automatique
|
|
294
|
+
await enduranceEmitter.emit(enduranceEventTypes.CORRECT_TEST, result);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
result.state = TestState.InProgress;
|
|
298
|
+
}
|
|
299
|
+
await result.save();
|
|
300
|
+
return res.status(200).json({
|
|
301
|
+
message: 'Réponse enregistrée',
|
|
302
|
+
response,
|
|
303
|
+
isLastQuestion: answeredQuestions === totalQuestions
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
console.error('Erreur lors de l\'enregistrement de la réponse :', err);
|
|
308
|
+
res.status(500).json({ message: 'Erreur interne du serveur' });
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const router = new ResultRouter();
|
|
314
|
+
export default router;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { EnduranceRouter, EnduranceAuthMiddleware } from 'endurance-core';
|
|
2
|
+
import User from '../models/user.model.js';
|
|
3
|
+
class UserRouter extends EnduranceRouter {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(EnduranceAuthMiddleware.getInstance());
|
|
6
|
+
}
|
|
7
|
+
setupRoutes() {
|
|
8
|
+
const authenticatedOptions = {
|
|
9
|
+
requireAuth: false,
|
|
10
|
+
permissions: []
|
|
11
|
+
};
|
|
12
|
+
// Lister tous les utilisateurs
|
|
13
|
+
this.get('/', authenticatedOptions, async (req, res) => {
|
|
14
|
+
try {
|
|
15
|
+
const users = await User.find();
|
|
16
|
+
res.status(200).json({ array: users });
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
console.error('Error when retrieving users: ', err);
|
|
20
|
+
res.status(500).json({ message: 'Internal server error' });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
// Créer un utilisateur
|
|
24
|
+
this.post('/create', authenticatedOptions, async (req, res) => {
|
|
25
|
+
const { firstName, lastName, email, companyId } = req.body;
|
|
26
|
+
if (!firstName || !lastName || !email || !companyId) {
|
|
27
|
+
return res.status(400).json({ message: 'Error, firstName, lastName, email and companyId are required' });
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const newUser = new User({ firstName, lastName, email, companyId });
|
|
31
|
+
await newUser.save();
|
|
32
|
+
res.status(201).json({ message: 'user created with sucess', user: newUser });
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.error('error when creating user : ', err);
|
|
36
|
+
res.status(500).json({ message: 'Internal server error' });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// Obtenir un utilisateur par son ID
|
|
40
|
+
this.get('/:id', authenticatedOptions, async (req, res) => {
|
|
41
|
+
const { id } = req.params;
|
|
42
|
+
try {
|
|
43
|
+
const user = await User.findById(id);
|
|
44
|
+
if (!user) {
|
|
45
|
+
return res.status(404).json({ message: 'no user founded with this id' });
|
|
46
|
+
}
|
|
47
|
+
res.status(200).json({ data: user });
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error('error when geting user : ', err);
|
|
51
|
+
res.status(500).json({ message: 'Internal server error' });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// Mettre à jour un utilisateur
|
|
55
|
+
this.put('/:id', authenticatedOptions, async (req, res) => {
|
|
56
|
+
const { id } = req.params;
|
|
57
|
+
const { firstName, lastName, email, companyId } = req.body;
|
|
58
|
+
try {
|
|
59
|
+
const user = await User.findById(id);
|
|
60
|
+
if (!user) {
|
|
61
|
+
return res.status(404).json({ message: 'no user founded with this id' });
|
|
62
|
+
}
|
|
63
|
+
const updateData = {
|
|
64
|
+
firstName: firstName || user.firstName,
|
|
65
|
+
lastName: lastName || user.lastName,
|
|
66
|
+
email: email || user.email,
|
|
67
|
+
companyId: companyId || user.companyId
|
|
68
|
+
};
|
|
69
|
+
await User.findByIdAndUpdate(id, updateData, { new: true });
|
|
70
|
+
const updatedUser = await User.findById(id);
|
|
71
|
+
res.status(200).json({ message: 'user updated', user: updatedUser });
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error('error when updating user : ', err);
|
|
75
|
+
res.status(500).json({ message: 'Internal server error' });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
// Supprimer un utilisateur
|
|
79
|
+
this.delete('/:id', authenticatedOptions, async (req, res) => {
|
|
80
|
+
const { id } = req.params;
|
|
81
|
+
try {
|
|
82
|
+
const user = await User.findByIdAndDelete(id);
|
|
83
|
+
if (!user) {
|
|
84
|
+
return res.status(404).json({ message: 'no user founded with this id' });
|
|
85
|
+
}
|
|
86
|
+
res.status(200).json({ message: 'user deleted', user });
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
console.error('error when deleting user : ', err);
|
|
90
|
+
res.status(500).json({ message: 'Internal server error' });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const router = new UserRouter();
|
|
96
|
+
export default router;
|
package/package.json
CHANGED
|
@@ -1,15 +1,80 @@
|
|
|
1
1
|
{
|
|
2
|
+
"type": "module",
|
|
2
3
|
"name": "@programisto/edrm-exams",
|
|
3
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
4
5
|
"publishConfig": {
|
|
5
6
|
"access": "public"
|
|
6
7
|
},
|
|
7
|
-
"description": "
|
|
8
|
-
"
|
|
9
|
-
"author": "",
|
|
10
|
-
"type": "commonjs",
|
|
11
|
-
"main": "index.js",
|
|
8
|
+
"description": "an api for online exams",
|
|
9
|
+
"main": "app.js",
|
|
12
10
|
"scripts": {
|
|
13
|
-
"
|
|
14
|
-
|
|
11
|
+
"start": "node ./dist/bin/www",
|
|
12
|
+
"dev": "tsc-watch --onSuccess \"node ./dist/bin/www\"",
|
|
13
|
+
"test": "mocha",
|
|
14
|
+
"build": "tsc && npm run copy-files",
|
|
15
|
+
"copy-files": "copyfiles -u 1 'src/**/*.txt' dist",
|
|
16
|
+
"lint": "eslint \"**/*.{ts,tsx}\"",
|
|
17
|
+
"prepare": "husky install"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"aws-sdk": "^2.1692.0",
|
|
21
|
+
"debug": "^4.3.7",
|
|
22
|
+
"edrm-mailer": "^0.4.5",
|
|
23
|
+
"edrm-user": "^0.4.9",
|
|
24
|
+
"endurance-core": "^0.4.25",
|
|
25
|
+
"fs": "^0.0.1-security",
|
|
26
|
+
"http": "^0.0.1-security",
|
|
27
|
+
"jsonwebtoken": "^9.0.2",
|
|
28
|
+
"mongoose": "^8.8.3",
|
|
29
|
+
"multer": "^1.4.5-lts.2",
|
|
30
|
+
"multer-s3": "^3.0.1",
|
|
31
|
+
"mustache": "^4.2.0",
|
|
32
|
+
"nodemailer": "^6.10.1",
|
|
33
|
+
"openai": "^4.100.0",
|
|
34
|
+
"path": "^0.12.7",
|
|
35
|
+
"to-regex-range": "^5.0.1",
|
|
36
|
+
"tsc-watch": "^6.2.1",
|
|
37
|
+
"url": "^0.11.4",
|
|
38
|
+
"uuid": "^11.0.3"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
42
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
43
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
44
|
+
"@semantic-release/git": "^10.0.1",
|
|
45
|
+
"@semantic-release/github": "^11.0.3",
|
|
46
|
+
"@semantic-release/npm": "^12.0.1",
|
|
47
|
+
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
48
|
+
"@types/node": "^22.15.3",
|
|
49
|
+
"commitlint": "^19.8.1",
|
|
50
|
+
"copyfiles": "^2.4.1",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^8.26.0",
|
|
52
|
+
"@typescript-eslint/parser": "^8.26.0",
|
|
53
|
+
"eslint": "^8.57.1",
|
|
54
|
+
"eslint-config-standard": "^17.1.0",
|
|
55
|
+
"eslint-plugin-import": "^2.31.0",
|
|
56
|
+
"eslint-plugin-n": "^16.6.2",
|
|
57
|
+
"eslint-plugin-promise": "^6.6.0",
|
|
58
|
+
"husky": "^9.1.7",
|
|
59
|
+
"mocha": "^11.0.1",
|
|
60
|
+
"nodemon": "^3.1.4",
|
|
61
|
+
"semantic-release": "^24.2.5",
|
|
62
|
+
"supertest": "^3.0.0",
|
|
63
|
+
"ts-node": "^10.9.2",
|
|
64
|
+
"typescript": "^5.8.3"
|
|
65
|
+
},
|
|
66
|
+
"repository": {
|
|
67
|
+
"type": "git",
|
|
68
|
+
"url": "git+https://github.com/programisto-labs/edrm-exams.git"
|
|
69
|
+
},
|
|
70
|
+
"author": "",
|
|
71
|
+
"license": "ISC",
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/programisto-labs/edrm-exams/issues"
|
|
74
|
+
},
|
|
75
|
+
"homepage": "https://github.com/programisto-labs/edrm-exams#readme",
|
|
76
|
+
"files": [
|
|
77
|
+
"dist",
|
|
78
|
+
"README.md"
|
|
79
|
+
]
|
|
15
80
|
}
|