data-primals-engine 1.3.3-rc.1 → 1.3.4

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.
@@ -2,6 +2,7 @@
2
2
  export const defaultModels = {
3
3
  permission: {
4
4
  "name": "permission",
5
+ "icon": "FaKey",
5
6
  "description": "",
6
7
  "fields": [
7
8
  {
@@ -17,6 +18,7 @@ export const defaultModels = {
17
18
  },
18
19
  role: {
19
20
  name: 'role',
21
+ "icon": "FaUserTag",
20
22
  "description": "",
21
23
  fields: [
22
24
  { name: 'name', type: 'string_t', required: true, unique: true, color: '#363636' },
@@ -26,6 +28,7 @@ export const defaultModels = {
26
28
  user: {
27
29
  name: 'user',
28
30
  "description": "",
31
+ "icon": "FaUser",
29
32
  locked: true,
30
33
  fields: [
31
34
  { name: 'username', type: 'string', required: true, unique: true, color: '#3C7D08' },
@@ -47,6 +50,7 @@ export const defaultModels = {
47
50
  ]
48
51
  },
49
52
  userPermission: {
53
+ "icon": "FaUserCheck",
50
54
  "name": "userPermission",
51
55
  "description": "Gère les exceptions aux permissions des rôles pour un utilisateur (ajouts ou retraits, permanents ou temporaires).",
52
56
  "fields": [
@@ -81,6 +85,7 @@ export const defaultModels = {
81
85
  },
82
86
  token: {
83
87
  name: 'token',
88
+ "icon": "FaKey",
84
89
  "description": "",
85
90
  fields: [
86
91
  { name: 'name', type: 'string' },
@@ -90,6 +95,7 @@ export const defaultModels = {
90
95
  },
91
96
  translation: {
92
97
  name: 'translation',
98
+ "icon": "FaLanguage",
93
99
  locked: true,
94
100
  "description": "",
95
101
  fields: [
@@ -100,6 +106,7 @@ export const defaultModels = {
100
106
  },
101
107
  lang: {
102
108
  name: 'lang',
109
+ "icon": "FaGlobe",
103
110
  locked: true,
104
111
  "description": "",
105
112
  fields: [
@@ -109,6 +116,7 @@ export const defaultModels = {
109
116
  },
110
117
  currency: {
111
118
  name: 'currency',
119
+ "icon": "FaMoneyBill",
112
120
  "description": "",
113
121
  locked: true,
114
122
  fields: [
@@ -121,6 +129,7 @@ export const defaultModels = {
121
129
  },
122
130
  channel: {
123
131
  name: 'channel',
132
+ "icon": "FaComments",
124
133
  "description": "",
125
134
  fields: [
126
135
  { name: 'name', type: 'string_t', required: true, unique: true }, // Nom du canal (ex: "email", "SMS")
@@ -130,6 +139,7 @@ export const defaultModels = {
130
139
  },
131
140
  message: {
132
141
  name: 'message',
142
+ "icon": "FaEnvelope",
133
143
  "description": "",
134
144
  locked: true,
135
145
  fields: [
@@ -148,6 +158,7 @@ export const defaultModels = {
148
158
  },
149
159
  alert: {
150
160
  name: "alert",
161
+ "icon": "FaBell",
151
162
  description: "Définit les règles pour les alertes et les insights automatiques.",
152
163
  fields: [
153
164
  { name: "name", type: "string", required: true, asMain: true },
@@ -186,6 +197,7 @@ export const defaultModels = {
186
197
  },
187
198
  env: {
188
199
  name: "env",
200
+ "icon": "FaCog",
189
201
  description: "Définit les variables d'environnement qui seront accessibles dans vos scripts et webhooks.",
190
202
  fields: [
191
203
  { name: "name", type: "string", required: true, unique: true, asMain: true },
@@ -194,6 +206,7 @@ export const defaultModels = {
194
206
  },
195
207
  webpage: {
196
208
  name: 'webpage',
209
+ "icon": "FaFileAlt",
197
210
  locked: true,
198
211
  "description": "",
199
212
  fields: [
@@ -210,6 +223,7 @@ export const defaultModels = {
210
223
  },
211
224
  content: {
212
225
  name: 'content',
226
+ "icon": "FaFileAlt",
213
227
  "description": "",
214
228
  fields: [
215
229
  { name: 'lang', type: 'relation', relation: 'lang' },
@@ -240,6 +254,7 @@ export const defaultModels = {
240
254
  },
241
255
  resource: {
242
256
  name: 'resource',
257
+ "icon": "FaBoxOpen",
243
258
  "description": "",
244
259
  fields: [
245
260
  { name: "source", type: "url"},
@@ -248,6 +263,7 @@ export const defaultModels = {
248
263
  },
249
264
  taxonomy: {
250
265
  name: 'taxonomy',
266
+ "icon": "FaTags",
251
267
  "description": "",
252
268
  fields: [
253
269
  { name: 'name', type: 'string_t', required: true, color: '#71A314' },
@@ -261,6 +277,7 @@ export const defaultModels = {
261
277
  contact: {
262
278
  locked: true,
263
279
  name: 'contact',
280
+ "icon": "FaAddressBook",
264
281
  "description": "",
265
282
  fields: [
266
283
  { name: 'legalName', type: 'string', asMain: true, color: '#D9D9D9' },
@@ -274,6 +291,7 @@ export const defaultModels = {
274
291
 
275
292
  location: {
276
293
  "name": "location",
294
+ "icon": "FaMapMarkerAlt",
277
295
  locked: true,
278
296
  "description": "",
279
297
  "fields": [
@@ -332,6 +350,7 @@ export const defaultModels = {
332
350
 
333
351
  brand: {
334
352
  name: 'brand',
353
+ "icon": "FaTrademark",
335
354
  "description": "",
336
355
  fields: [
337
356
  { name: 'name', type: 'string', required: true },
@@ -342,6 +361,7 @@ export const defaultModels = {
342
361
 
343
362
  product: {
344
363
  name: 'product',
364
+ "icon": "FaShoppingBag",
345
365
  "description": "",
346
366
  fields: [
347
367
  { name: 'name', type: 'string_t', required: true },
@@ -359,6 +379,7 @@ export const defaultModels = {
359
379
  },
360
380
  productVariant: {
361
381
  name: 'productVariant',
382
+ "icon": "FaBox",
362
383
  "description": "",
363
384
  fields: [
364
385
  { name: 'product', type: 'relation', relation: 'product', required: true },
@@ -374,6 +395,7 @@ export const defaultModels = {
374
395
  },
375
396
  cart: {
376
397
  name: 'cart',
398
+ "icon": "FaShoppingCart",
377
399
  "description": "",
378
400
  fields: [
379
401
  { name: 'user', type: 'relation', relation: 'user', required: true },
@@ -385,6 +407,7 @@ export const defaultModels = {
385
407
  },
386
408
  cartItem: {
387
409
  name: 'cartItem',
410
+ "icon": "FaShoppingBasket",
388
411
  "description": "",
389
412
  fields: [
390
413
  { name: 'product', type: 'relation', relation: 'product', required: true },
@@ -394,6 +417,7 @@ export const defaultModels = {
394
417
  },
395
418
  discount: {
396
419
  name: "discount",
420
+ "icon": "FaTicketAlt",
397
421
  locked: true,
398
422
  "description": "",
399
423
  fields: [
@@ -411,6 +435,7 @@ export const defaultModels = {
411
435
  },
412
436
  order: {
413
437
  name: "order",
438
+ "icon": "FaClipboardList",
414
439
  locked: true,
415
440
  "description": "",
416
441
  fields: [
@@ -432,6 +457,7 @@ export const defaultModels = {
432
457
  },
433
458
  invoice: {
434
459
  name: 'invoice',
460
+ "icon": "FaFileInvoice",
435
461
  "description": "",
436
462
  fields: [
437
463
  { name: 'order', type: 'relation', relation: 'order', required: true },
@@ -443,6 +469,7 @@ export const defaultModels = {
443
469
  },
444
470
  userSubscription: {
445
471
  name: 'userSubscription',
472
+ "icon": "FaCalendarCheck",
446
473
  "description": "",
447
474
  locked: true,
448
475
  fields: [
@@ -463,6 +490,7 @@ export const defaultModels = {
463
490
  },
464
491
  stock: {
465
492
  name: 'stock',
493
+ "icon": "FaWarehouse",
466
494
  "description": "",
467
495
  fields: [
468
496
  { name: 'product', type: 'relation', relation: 'product', required: true },
@@ -474,6 +502,7 @@ export const defaultModels = {
474
502
  },
475
503
  stockAlert: {
476
504
  name: 'stockAlert',
505
+ "icon": "FaExclamationTriangle",
477
506
  "description": "",
478
507
  fields: [
479
508
  { name: 'user', type: 'relation', relation: 'user', required: true },
@@ -484,6 +513,7 @@ export const defaultModels = {
484
513
  },
485
514
  shipment: {
486
515
  name: 'shipment',
516
+ "icon": "FaTruck",
487
517
  "description": "",
488
518
  fields: [
489
519
  { name: 'order', type: 'relation', relation: 'order', required: true },
@@ -497,6 +527,7 @@ export const defaultModels = {
497
527
  warehouse: {
498
528
  name: 'warehouse',
499
529
  "description": "",
530
+ "icon": "FaWarehouse",
500
531
  fields: [
501
532
  { name: 'name', type: 'string_t', required: true },
502
533
  { name: 'location', type: 'relation', relation: 'location' },
@@ -506,6 +537,7 @@ export const defaultModels = {
506
537
  'return': {
507
538
  name: "return",
508
539
  "description": "",
540
+ "icon": "FaUndo",
509
541
  fields: [
510
542
  { "name": "order", "type": "relation", "relation": "order", "required": true },
511
543
  { "name": "user", "type": "relation", relation: "user" },
@@ -519,6 +551,7 @@ export const defaultModels = {
519
551
  },
520
552
  returnItem: {
521
553
  name: 'returnItem',
554
+ "icon": "FaBoxOpen",
522
555
  "description": "",
523
556
  fields: [
524
557
  { name: 'return', type: 'relation', relation: 'return', required: true },
@@ -530,6 +563,7 @@ export const defaultModels = {
530
563
  },
531
564
  ticket: {
532
565
  name: 'ticket',
566
+ "icon": "FaTicketAlt",
533
567
  "description": "",
534
568
  locked: true,
535
569
  fields: [
@@ -547,6 +581,7 @@ export const defaultModels = {
547
581
  },
548
582
  review: {
549
583
  name: "review",
584
+ "icon": "FaStar",
550
585
  "description": "",
551
586
  fields: [
552
587
  { "name": "user", "type": "relation", relation: "user" },
@@ -559,6 +594,7 @@ export const defaultModels = {
559
594
  },
560
595
  device: {
561
596
  name: "device",
597
+ "icon": "FaMobile",
562
598
  "description": "",
563
599
  fields: [
564
600
  { "name": "location", "type": "relation", relation: 'location' },
@@ -568,6 +604,7 @@ export const defaultModels = {
568
604
  // Modèle pour l'exercice comptable et l'entreprise
569
605
  accountingExercise: {
570
606
  name: 'accountingExercise',
607
+ "icon": "FaBook",
571
608
  description: "Représente un exercice comptable pour une entreprise donnée.",
572
609
  fields: [
573
610
  { name: 'name', type: 'string_t', 'required': true, unique: true, hint: "Intitulé de l'exercice comptable" },
@@ -581,6 +618,7 @@ export const defaultModels = {
581
618
  // Modèle pour définir la structure des lignes comptables (le "plan")
582
619
  accountingLineItem: {
583
620
  name: 'accountingLineItem',
621
+ "icon": "FaListAlt",
584
622
  description: "Définit une ligne/catégorie dans un document comptable.",
585
623
  locked: true, // Probablement géré par l'application, pas par l'utilisateur final
586
624
  fields: [
@@ -610,6 +648,7 @@ export const defaultModels = {
610
648
  },
611
649
  accountingEntry: {
612
650
  "name": "accountingEntry",
651
+ "icon": "FaPenAlt",
613
652
  "description": "",
614
653
  "fields": [
615
654
  {
@@ -679,6 +718,7 @@ export const defaultModels = {
679
718
  },
680
719
  employee: {
681
720
  "name": "employee",
721
+ "icon": "FaUserTie",
682
722
  "description": "",
683
723
  "fields": [
684
724
  {
@@ -819,6 +859,7 @@ export const defaultModels = {
819
859
  },
820
860
  workflow: {
821
861
  name: 'workflow',
862
+ "icon": "FaProjectDiagram",
822
863
  description: "Defines an automated process.",
823
864
  fields: [
824
865
  { name: 'name', type: 'string_t', required: true, hint: "Unique name for the workflow (e.g., 'Order Validation', 'Low Stock Notification')." },
@@ -828,6 +869,7 @@ export const defaultModels = {
828
869
  },
829
870
  workflowTrigger: {
830
871
  name: 'workflowTrigger',
872
+ "icon": "FaPlay",
831
873
  description: "Represents an event that can initiate a workflow.",
832
874
  fields: [
833
875
  { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
@@ -879,6 +921,7 @@ export const defaultModels = {
879
921
  },
880
922
  workflowStep: {
881
923
  name: 'workflowStep',
924
+ "icon": "FaStepForward",
882
925
  description: "A single step within a workflow process.",
883
926
  fields: [
884
927
  { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
@@ -892,6 +935,7 @@ export const defaultModels = {
892
935
  },
893
936
  workflowAction: {
894
937
  name: 'workflowAction',
938
+ "icon": "FaCogs",
895
939
  description: "Defines a specific operation to be performed by a workflow step.",
896
940
  fields: [
897
941
  { name: 'name', type: 'string_t', required: true, hint: "Name of the action (e.g., 'Update Order Status', 'Send Email', 'Call Payment API')." },
@@ -991,6 +1035,7 @@ export const defaultModels = {
991
1035
 
992
1036
  workflowRun: {
993
1037
  name: 'workflowRun',
1038
+ "icon": "FaRunning",
994
1039
  description: "Tracks a specific execution instance of a workflow.",
995
1040
  fields: [
996
1041
  { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow definition that was executed." },
@@ -1013,6 +1058,7 @@ export const defaultModels = {
1013
1058
  },
1014
1059
  dashboard:{
1015
1060
  name: 'dashboard', // Nom technique du modèle
1061
+ "icon": "FaTachometerAlt",
1016
1062
  description: "Configuration d'un tableau de bord personnalisé par l'utilisateur.", // Description du modèle
1017
1063
  locked: false, // Indique si le modèle peut être modifié par l'utilisateur (false = modifiable)
1018
1064
  fields: [
@@ -1052,6 +1098,7 @@ export const defaultModels = {
1052
1098
  },
1053
1099
  'request': {
1054
1100
  name: 'request',
1101
+ "icon": "FaExchangeAlt",
1055
1102
  description: "Journal des requêtes reçues par l'API.",
1056
1103
  locked: true, // Géré par le système, non modifiable directement par l'utilisateur via l'UI standard
1057
1104
  fields: [
@@ -1137,6 +1184,7 @@ export const defaultModels = {
1137
1184
 
1138
1185
  kpi : {
1139
1186
  name: 'kpi',
1187
+ "icon": "FaChartLine",
1140
1188
  description: "Configuration d'un Indicateur Clé de Performance (KPI)",
1141
1189
  fields: [
1142
1190
  { name: 'name', type: 'string_t', required: true, hint: "Nom affiché du KPI (ex: Chiffre d'affaires total)" },
@@ -1200,6 +1248,7 @@ export const defaultModels = {
1200
1248
  },
1201
1249
  imageGallery: {
1202
1250
  name: 'imageGallery',
1251
+ "icon": "FaImages",
1203
1252
  description: "Représente une galerie d'images avec un titre et une description.",
1204
1253
  locked: false, // Les utilisateurs peuvent créer/gérer leurs galeries
1205
1254
  fields: [
@@ -1241,6 +1290,7 @@ export const defaultModels = {
1241
1290
  },
1242
1291
  budget: {
1243
1292
  name: 'budget',
1293
+ "icon": "FaMoneyCheck",
1244
1294
  description: "Un budget permet de lister vos transactions personnelles.",
1245
1295
  fields: [
1246
1296
  {
@@ -1312,6 +1362,7 @@ export const defaultModels = {
1312
1362
  },
1313
1363
  event: {
1314
1364
  "name": "event",
1365
+ "icon": "FaCalendar",
1315
1366
  "description": "A model for managing events, conferences, meetups, and gatherings.",
1316
1367
  "fields": [
1317
1368
  {
@@ -1424,6 +1475,7 @@ export const defaultModels = {
1424
1475
  },
1425
1476
  endpoint: {
1426
1477
  name: "endpoint",
1478
+ "icon": "FaCode",
1427
1479
  description: "Defines custom API endpoints that execute a server-side script.",
1428
1480
  fields: [
1429
1481
  {
package/src/filter.js CHANGED
@@ -1,3 +1,4 @@
1
+ import safeRegex from 'safe-regex';
1
2
  /**
2
3
  * Evaluates a single condition against form data.
3
4
  * @param {object} currentModelDef - The definition of the current model.
@@ -139,8 +140,8 @@ const evaluateSingleCondition = (currentModelDef, condition, formData, allModels
139
140
  function evaluateComparison(operator, targetValue, processedConditionValue, condition) {
140
141
  try {
141
142
  switch (typeof operator === 'object' ? Object.keys(operator)[0] : null) {
142
- case '$eq': return targetValue == processedConditionValue;
143
- case '$ne': return targetValue != processedConditionValue;
143
+ case '$eq': return targetValue === processedConditionValue;
144
+ case '$ne': return targetValue !== processedConditionValue;
144
145
  case '$gt': return targetValue > processedConditionValue;
145
146
  case '$lt': return targetValue < processedConditionValue;
146
147
  case '$gte': return targetValue >= processedConditionValue;
@@ -149,8 +150,11 @@ const evaluateSingleCondition = (currentModelDef, condition, formData, allModels
149
150
  if (typeof targetValue !== 'string') return false;
150
151
  if (typeof processedConditionValue !== 'string') return false;
151
152
  try {
152
- const regex = new RegExp(processedConditionValue, 'i');
153
- return regex.test(targetValue);
153
+ if( safeRegex(processedConditionValue)) {
154
+ const regex = new RegExp(processedConditionValue, 'i');
155
+ return regex.test(targetValue);
156
+ }
157
+ return false;
154
158
  } catch (e) {
155
159
  logClientEvalWarning(`Invalid regex pattern: ${processedConditionValue}`, condition);
156
160
  return false;
@@ -175,63 +179,70 @@ export const isConditionMet = (model, cond, formData, allModels, user) => {
175
179
 
176
180
  if (!condition) return true;
177
181
 
178
- // Cas 0: Condition est une valeur primitive (string, number, boolean)
179
- // On la considère comme toujours vraie (comportement de searchData)
180
182
  if (typeof condition !== 'object' || condition === null) {
181
183
  return true;
182
184
  }
183
185
 
184
- // Cas 1: Condition simple {field: value} transformée en {field: {$eq: value}}
185
- if (typeof condition === 'object' && !Array.isArray(condition)) {
186
+ // Cas spécial: Évaluation sans modèle (ex: pour les webhooks la condition est déjà résolue)
187
+ // Dans ce mode, la condition doit être un objet avec un seul opérateur.
188
+ if (!model) {
186
189
  const keys = Object.keys(condition);
187
-
188
- // Cas spécial pour les conditions de type {field: value} (pas d'opérateur $)
189
- if (keys.length === 1 && !keys[0].startsWith('$') &&
190
- typeof condition[keys[0]] !== 'object') {
191
- const fieldName = keys[0];
192
- const value = condition[fieldName];
193
-
194
- // Si la valeur est null/undefined, on vérifie simplement l'existence
195
- if (value === null || value === undefined) {
196
- return formData[fieldName] === value;
197
- }
198
-
199
- // Sinon on fait une comparaison d'égalité simple
200
- return formData[fieldName] == value;
190
+ if (keys.length !== 1 || !keys[0].startsWith('$')) {
191
+ console.warn('[isConditionMet] Condition invalide pour une évaluation sans modèle. Attendu : { "$opérateur": [...] }. Reçu :', condition);
192
+ return false; // Plus sûr que true pour éviter les faux positifs
201
193
  }
202
194
 
203
- // Cas spécial pour les tableaux - vérifie si la valeur est incluse
204
- if (keys.length === 1 && !keys[0].startsWith('$') &&
205
- Array.isArray(condition[keys[0]])) {
206
- const fieldName = keys[0];
207
- const values = condition[fieldName];
208
- const fieldValue = formData[fieldName];
209
-
210
- // Si le champ est aussi un tableau, vérifie l'intersection
211
- if (Array.isArray(fieldValue)) {
212
- return fieldValue.some(v => values.includes(v));
213
- }
195
+ const operator = keys[0];
196
+ const operands = condition[operator];
197
+
198
+ switch (operator) {
199
+ // Opérateurs logiques (récursifs)
200
+ case '$and':
201
+ return Array.isArray(operands) && operands.every(sub => isConditionMet(null, sub, formData, allModels, user));
202
+ case '$or':
203
+ return Array.isArray(operands) && operands.some(sub => isConditionMet(null, sub, formData, allModels, user));
204
+ case '$not':
205
+ return !isConditionMet(null, operands, formData, allModels, user);
206
+ case '$nor':
207
+ return Array.isArray(operands) && !operands.some(sub => isConditionMet(null, sub, formData, allModels, user));
208
+
209
+ // Opérateurs de comparaison (terminaux)
210
+ case '$eq':
211
+ return Array.isArray(operands) && operands[0] === operands[1];
212
+ case '$ne':
213
+ return Array.isArray(operands) && operands[0] !== operands[1];
214
+ case '$in':
215
+ return Array.isArray(operands) && Array.isArray(operands[1]) && operands[1].includes(operands[0]);
216
+ case '$nin':
217
+ return Array.isArray(operands) && Array.isArray(operands[1]) && !operands[1].includes(operands[0]);
218
+ case '$gt':
219
+ return Array.isArray(operands) && operands[0] > operands[1];
220
+ case '$gte':
221
+ return Array.isArray(operands) && operands[0] >= operands[1];
222
+ case '$lt':
223
+ return Array.isArray(operands) && operands[0] < operands[1];
224
+ case '$lte':
225
+ return Array.isArray(operands) && operands[0] <= operands[1];
214
226
 
215
- // Sinon vérifie si la valeur est dans le tableau
216
- return values.includes(fieldValue);
227
+ default:
228
+ console.warn(`[isConditionMet] Opérateur non supporté '${operator}' pour une évaluation sans modèle.`);
229
+ return false;
217
230
  }
218
231
  }
219
232
 
220
- // Cas 2: Opérateurs logiques ($and, $or, $not, $nor)
233
+ // --- Logique existante pour l'évaluation AVEC modèle ---
234
+
221
235
  if (condition.$and && Array.isArray(condition.$and)) {
222
236
  if (condition.$and.length === 0) return true;
223
237
  return condition.$and.every(sub => isConditionMet(model, sub, formData, allModels, user));
224
238
  }
225
-
226
239
  if (condition.$or && Array.isArray(condition.$or)) {
227
240
  if (condition.$or.length === 0) return false;
228
241
  return condition.$or.some(sub => isConditionMet(model, sub, formData, allModels, user));
229
242
  }
230
-
231
243
  if (condition.$not) {
232
244
  return !isConditionMet(model, condition.$not, formData, allModels, user);
233
245
  }
234
-
235
246
  if (condition.$nor && Array.isArray(condition.$nor)) {
236
247
  if (condition.$nor.length === 0) return true;
237
248
  return !condition.$nor.some(sub => isConditionMet(model, sub, formData, allModels, user));
@@ -246,6 +257,5 @@ export const isConditionMet = (model, cond, formData, allModels, user) => {
246
257
  }
247
258
  }
248
259
 
249
- // Cas 4: Tous les autres cas (conditions normales avec opérateurs)
250
260
  return evaluateSingleCondition(model, condition, formData, allModels, user);
251
261
  };
package/src/i18n.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import i18n from "i18next";
2
- import {Trans, useTranslation, initReactI18next} from "react-i18next";
2
+ import {Trans, useTranslation,I18nextProvider, initReactI18next} from "react-i18next";
3
3
  import LanguageDetector from "i18next-browser-languagedetector";
4
4
 
5
5
  export const translations = {
@@ -12441,5 +12441,5 @@ i18n
12441
12441
  }
12442
12442
  });
12443
12443
 
12444
- export {Trans, useTranslation};
12444
+ export {Trans, useTranslation, I18nextProvider};
12445
12445
  export default i18n;
@@ -1075,7 +1075,8 @@ export const editModel = async (user, id, data) => {
1075
1075
  export async function middlewareEndpointAuthenticator(req, res, next) {
1076
1076
  const { path } = req.params;
1077
1077
  const method = req.method.toUpperCase();
1078
- const datasCollection = getCollection('datas');
1078
+ const user = await engine.userProvider.findUserByUsername(req.query._user || req.params.user || req.me.username);
1079
+ const datasCollection = await getCollectionForUser(user);
1079
1080
 
1080
1081
  try {
1081
1082
  const endpointDef = await datasCollection.findOne({
@@ -1137,7 +1138,9 @@ export async function handleCustomEndpointRequest(req, res) {
1137
1138
  // 2. Préparer le contexte pour le script
1138
1139
  const contextData = {
1139
1140
  request: {
1140
- body: req.fields,
1141
+ // MODIFICATION: Utiliser req.body si disponible (pour les requêtes JSON comme les webhooks Stripe),
1142
+ // sinon, utiliser req.fields (pour les données de formulaire).
1143
+ body: (req.body && Object.keys(req.body).length > 0) ? req.body : (req.fields || {}),
1141
1144
  query: req.query,
1142
1145
  params: req.params,
1143
1146
  headers: req.headers
@@ -1276,7 +1279,7 @@ export async function onInit(defaultEngine) {
1276
1279
 
1277
1280
  const objectKeys = Object.keys(modelStructure);
1278
1281
 
1279
- if( objectKeys.find(o => !["name", "_user", "history", "locked", "_id", "description", "maxRequestData", "fields"].includes(o)) ){
1282
+ if( objectKeys.find(o => !["name", "_user", "icon", "history", "locked", "_id", "description", "maxRequestData", "fields"].includes(o)) ){
1280
1283
  throw new Error(i18n.t('api.model.invalidStructure'));
1281
1284
  }
1282
1285
 
@@ -161,7 +161,8 @@ export async function registerRoutes(engine){
161
161
 
162
162
  logger = engine.getComponent(Logger);
163
163
 
164
- engine.all('/api/actions/:path', [middlewareEndpointAuthenticator, userInitiator], handleCustomEndpointRequest);
164
+ engine.all('/api/actions/:user/:path', [middlewareEndpointAuthenticator, userInitiator], handleCustomEndpointRequest);
165
+ engine.all('/api/actions/:path', [middlewareAuthenticator, middlewareEndpointAuthenticator, userInitiator], handleCustomEndpointRequest);
165
166
  engine.post('/api/demo/initialize', [middlewareAuthenticator, userInitiator], handleDemoInitialization);
166
167
 
167
168
  engine.post('/api/magnets', [middlewareAuthenticator, userInitiator], async (req, res) => {
@@ -872,7 +873,7 @@ export async function registerRoutes(engine){
872
873
  await cancelAlerts(req.me);
873
874
 
874
875
  await getPromise();
875
- await Event.Trigger('jobAddUserData', req.me.username);
876
+ await Event.Trigger('OnDemoUserAdded', req.me.username);
876
877
  }else{
877
878
  await getPromise();
878
879
  }