data-primals-engine 1.4.1 → 1.4.3
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 +37 -22
- package/client/package-lock.json +33 -0
- package/client/package.json +1 -0
- package/client/src/App.scss +12 -4
- package/client/src/AssistantChat.jsx +48 -5
- package/client/src/AssistantChat.scss +0 -1
- package/client/src/ChartConfigModal.jsx +34 -9
- package/client/src/ConditionBuilder.jsx +1 -1
- package/client/src/ConditionBuilder2.jsx +2 -1
- package/client/src/Dashboard.jsx +396 -349
- package/client/src/DashboardChart.jsx +91 -12
- package/client/src/DataEditor.jsx +376 -368
- package/client/src/DataLayout.jsx +3 -2
- package/client/src/DataTable.jsx +60 -31
- package/client/src/Field.jsx +1788 -1782
- package/client/src/GeolocationField.jsx +94 -0
- package/client/src/ModelCreatorField.jsx +1 -0
- package/client/src/RelationField.jsx +2 -2
- package/client/src/constants.js +2 -2
- package/client/src/contexts/UIContext.jsx +5 -2
- package/client/src/filter.js +0 -155
- package/client/src/translations.js +16828 -16750
- package/package.json +10 -2
- package/src/config.js +2 -2
- package/src/constants.js +262 -4
- package/src/core.js +21 -3
- package/src/defaultModels.js +12 -12
- package/src/engine.js +7 -1
- package/src/events.js +4 -3
- package/src/filter.js +272 -260
- package/src/i18n.js +187 -177
- package/src/middlewares/middleware-mongodb.js +3 -1
- package/src/modules/assistant/assistant.js +131 -42
- package/src/modules/bucket.js +3 -2
- package/src/modules/data/data.backup.js +374 -0
- package/src/modules/data/data.core.js +2 -1
- package/src/modules/data/data.history.js +11 -8
- package/src/modules/data/data.js +190 -4551
- package/src/modules/data/data.operations.js +3000 -0
- package/src/modules/data/data.relations.js +687 -0
- package/src/modules/data/data.routes.js +132 -38
- package/src/modules/data/data.scheduling.js +274 -0
- package/src/modules/data/data.validation.js +248 -0
- package/src/modules/data/index.js +29 -1
- package/src/modules/user.js +2 -1
- package/src/modules/workflow.js +3 -2
- package/src/services/stripe.js +3 -2
- package/swagger-en.yml +133 -0
- package/test/model.integration.test.js +377 -221
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "data-primals-engine is a package responsible from handling large amount of data using MongoDB in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation. It also has integrated AI assistant.",
|
|
5
5
|
"main": "src/engine.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,15 @@
|
|
|
35
35
|
"xml2js": ">=0.5.0"
|
|
36
36
|
},
|
|
37
37
|
"overrides": {
|
|
38
|
-
"
|
|
38
|
+
"react-syntax-highlighter": {
|
|
39
|
+
"prismjs": "1.30.0"
|
|
40
|
+
},
|
|
41
|
+
"react-code-blocks": {
|
|
42
|
+
"prismjs": "1.30.0"
|
|
43
|
+
},
|
|
44
|
+
"refractor": {
|
|
45
|
+
"prismjs": "1.30.0"
|
|
46
|
+
}
|
|
39
47
|
},
|
|
40
48
|
"repository": {
|
|
41
49
|
"type": "git",
|
package/src/config.js
CHANGED
package/src/constants.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import {event_trigger} from "./core.js";
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Enables auto-installation at startup
|
|
5
3
|
* @type {boolean}
|
|
@@ -300,10 +298,270 @@ metaModels['erp'] = { load: [ 'accountingExercise', 'accountingLineItem', 'accou
|
|
|
300
298
|
* Available model field attributes
|
|
301
299
|
* @type {string[]}
|
|
302
300
|
*/
|
|
303
|
-
export const allowedFields = ['locked', 'hiddenable', 'anonymized', 'condition', 'color', 'index', 'type', 'required', 'hint', 'default', 'validate', 'unique', 'name', 'placeholder', 'asMain'];
|
|
301
|
+
export const allowedFields = ['locked', 'hiddenable', 'anonymized', 'condition', 'color', 'index', 'indexType', 'type', 'required', 'hint', 'default', 'validate', 'unique', 'name', 'placeholder', 'asMain'];
|
|
304
302
|
|
|
305
303
|
|
|
306
304
|
|
|
307
305
|
export const getHost = () => {
|
|
308
306
|
return process.env.HOST || host || 'localhost';
|
|
309
|
-
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Configuration of MongoDB filters
|
|
311
|
+
*/
|
|
312
|
+
export const MONGO_CALC_OPERATORS = {
|
|
313
|
+
$find: {
|
|
314
|
+
label: 'Find in relation',
|
|
315
|
+
description: 'Recherche dans une relation/tableau',
|
|
316
|
+
supportsNesting: true,
|
|
317
|
+
multi: false,
|
|
318
|
+
isFindOperator: true // Nouvelle propriété pour identifier les opérateurs $find
|
|
319
|
+
},
|
|
320
|
+
'$regexMatch': {
|
|
321
|
+
label: 'Find by regex',
|
|
322
|
+
description: 'Find a string matching a regular expression (Ecmascript)',
|
|
323
|
+
args: 2, // input et regex
|
|
324
|
+
specialStructure: true // Indique une structure spéciale
|
|
325
|
+
},
|
|
326
|
+
$and: {
|
|
327
|
+
label: 'Et (and)',
|
|
328
|
+
description: 'Renvoie vrai si toutes les conditions sont vérifiées',
|
|
329
|
+
args: 1,
|
|
330
|
+
multi: true
|
|
331
|
+
},
|
|
332
|
+
$or: {
|
|
333
|
+
label: 'Ou (or)',
|
|
334
|
+
description: 'Renvoie vrai si au moins une des conditions est vérifiée.',
|
|
335
|
+
args: 1,
|
|
336
|
+
multi: true
|
|
337
|
+
},
|
|
338
|
+
$not: {label: 'Non (not)', description: 'Inverse la condition (ex: non égal à).', args: 1, multi: true},
|
|
339
|
+
$nor: {
|
|
340
|
+
label: 'Ou Non (nor)',
|
|
341
|
+
description: 'Renvoie vrai si aucune des conditions n\'est vérifiée',
|
|
342
|
+
args: 1,
|
|
343
|
+
multi: true
|
|
344
|
+
},
|
|
345
|
+
$eq: {label: '=', multi: false, args: 2},
|
|
346
|
+
$ne: {label: '!=', multi: false, args: 2},
|
|
347
|
+
$gt: {label: '>', multi: false, args: 2},
|
|
348
|
+
$gte: {label: '>=', multi: false, args: 2},
|
|
349
|
+
$lt: {label: '<', multi: false, args: 2},
|
|
350
|
+
$lte: {label: '<=', multi: false, args: 2},
|
|
351
|
+
$in: {label: 'in', multi: true, args: 2},
|
|
352
|
+
$nin: {label: 'nin', multi: true, args: 2},
|
|
353
|
+
$all: {label: 'afll', multi: true},
|
|
354
|
+
$size: {
|
|
355
|
+
label: 'size',
|
|
356
|
+
multi: false,
|
|
357
|
+
description: 'Renvoie le nombre d\'éléments dans un tableau',
|
|
358
|
+
disableAdvancedValue: true
|
|
359
|
+
},
|
|
360
|
+
$elemMatch: {label: 'elemMatch', multi: true},
|
|
361
|
+
$type: {
|
|
362
|
+
label: 'type',
|
|
363
|
+
description: 'Renvoie le type BSON de l\'élément',
|
|
364
|
+
multi: false,
|
|
365
|
+
disableAdvancedValue: true
|
|
366
|
+
},
|
|
367
|
+
$add: {label: '+', multi: true},
|
|
368
|
+
$subtract: {label: '-', multi: false, args: 2},
|
|
369
|
+
$multiply: {label: '*', multi: true},
|
|
370
|
+
$divide: {label: '/', multi: false, args: 2},
|
|
371
|
+
$mod: {label: '%', multi: false, args: 2},
|
|
372
|
+
$pow: {label: 'pow', multi: false},
|
|
373
|
+
$sqrt: {label: 'sqrt', multi: false},
|
|
374
|
+
$exp: {label: 'exp', multi: false},
|
|
375
|
+
$abs: {label: 'abs', multi: false},
|
|
376
|
+
$ceil: {label: 'ceil', multi: false},
|
|
377
|
+
$floor: {label: 'floor', multi: false},
|
|
378
|
+
$ln: {label: 'ln', multi: false},
|
|
379
|
+
$log10: {label: 'log', multi: false},
|
|
380
|
+
$concat: {label: 'concat', multi: true},
|
|
381
|
+
|
|
382
|
+
// Date-specific
|
|
383
|
+
$year: {label: 'year', multi: false, isDate: true},
|
|
384
|
+
$month: {label: 'month', multi: false, isDate: true},
|
|
385
|
+
$dayOfMonth: {label: 'dayOfMonth', multi: false, isDate: true},
|
|
386
|
+
$hour: {label: 'hour', multi: false, isDate: true},
|
|
387
|
+
$minute: {label: 'minute', multi: false, isDate: true},
|
|
388
|
+
$second: {label: 'second', multi: false, isDate: true},
|
|
389
|
+
$millisecond: {label: 'ms', multi: false, isDate: true},
|
|
390
|
+
// Date operators
|
|
391
|
+
$dateAdd: {
|
|
392
|
+
label: 'Add to date',
|
|
393
|
+
description: 'Adds a duration to a date',
|
|
394
|
+
isDate: true,
|
|
395
|
+
specialStructure: true,
|
|
396
|
+
args: [
|
|
397
|
+
{name: 'startDate', label: 'Start Date', type: 'date'},
|
|
398
|
+
{
|
|
399
|
+
name: 'unit',
|
|
400
|
+
label: 'Unit',
|
|
401
|
+
type: 'select',
|
|
402
|
+
options: ['year', 'month', 'day', 'hour', 'minute', 'second']
|
|
403
|
+
},
|
|
404
|
+
{name: 'amount', label: 'Amount', type: 'number'},
|
|
405
|
+
{name: 'timezone', label: 'Timezone', type: 'text', optional: true}
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
$dateSubtract: {
|
|
409
|
+
label: 'Subtract from date',
|
|
410
|
+
description: 'Subtracts a duration from a date',
|
|
411
|
+
isDate: true,
|
|
412
|
+
specialStructure: true,
|
|
413
|
+
args: [
|
|
414
|
+
{name: 'startDate', label: 'Start Date', type: 'date'},
|
|
415
|
+
{
|
|
416
|
+
name: 'unit',
|
|
417
|
+
label: 'Unit',
|
|
418
|
+
type: 'select',
|
|
419
|
+
options: ['year', 'month', 'day', 'hour', 'minute', 'second']
|
|
420
|
+
},
|
|
421
|
+
{name: 'amount', label: 'Amount', type: 'number'},
|
|
422
|
+
{name: 'timezone', label: 'Timezone', type: 'text', optional: true}
|
|
423
|
+
]
|
|
424
|
+
},
|
|
425
|
+
$dateDiff: {
|
|
426
|
+
label: 'Date Difference',
|
|
427
|
+
description: 'Calculates the difference between two dates in specified units',
|
|
428
|
+
isDate: true,
|
|
429
|
+
specialStructure: true,
|
|
430
|
+
args: [
|
|
431
|
+
{
|
|
432
|
+
name: 'startDate',
|
|
433
|
+
label: 'Start Date',
|
|
434
|
+
type: 'date',
|
|
435
|
+
description: 'The starting date (inclusive)'
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
name: 'endDate',
|
|
439
|
+
label: 'End Date',
|
|
440
|
+
type: 'date',
|
|
441
|
+
description: 'The ending date (exclusive)'
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: 'unit',
|
|
445
|
+
label: 'Unit',
|
|
446
|
+
type: 'select',
|
|
447
|
+
options: ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'],
|
|
448
|
+
description: 'The unit for the result'
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
name: 'timezone',
|
|
452
|
+
label: 'Timezone',
|
|
453
|
+
type: 'text',
|
|
454
|
+
optional: true,
|
|
455
|
+
description: 'The timezone (e.g. "Europe/Paris")'
|
|
456
|
+
}
|
|
457
|
+
]
|
|
458
|
+
},
|
|
459
|
+
$dateToString: {
|
|
460
|
+
label: 'Format date as string',
|
|
461
|
+
description: 'Formats a date as a string',
|
|
462
|
+
isDate: true,
|
|
463
|
+
specialStructure: true,
|
|
464
|
+
args: [
|
|
465
|
+
{
|
|
466
|
+
name: 'date',
|
|
467
|
+
label: 'Date',
|
|
468
|
+
type: 'date'
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: 'format',
|
|
472
|
+
label: 'Format',
|
|
473
|
+
optional: true,
|
|
474
|
+
type: 'text'
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: 'timezone',
|
|
478
|
+
label: 'Timezone',
|
|
479
|
+
type: 'text',
|
|
480
|
+
optional: true,
|
|
481
|
+
description: 'The timezone (e.g. "Europe/Paris")'
|
|
482
|
+
}
|
|
483
|
+
]
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
// Converters
|
|
487
|
+
$toBool: {label: 'toBool', multi: false, converter: true},
|
|
488
|
+
$toString: {label: 'toString', multi: false, converter: true},
|
|
489
|
+
$toInt: {label: 'toInt', multi: false, converter: true},
|
|
490
|
+
$toDouble: {label: 'toDouble', multi: false, converter: true},
|
|
491
|
+
|
|
492
|
+
// --- Special Query Operators (not for $expr) ---
|
|
493
|
+
// These operators are handled by a standard $match stage, not inside $expr.
|
|
494
|
+
// The UI should use them to construct parts of the main filter object.
|
|
495
|
+
$regex: {
|
|
496
|
+
label: 'Regex',
|
|
497
|
+
description: 'Matches strings using a regular expression. Applied to a specific field.',
|
|
498
|
+
isQueryOperator: true,
|
|
499
|
+
specialStructure: true,
|
|
500
|
+
args: [
|
|
501
|
+
{ name: 'pattern', label: 'Pattern', type: 'text', description: 'The regex pattern.' },
|
|
502
|
+
{ name: 'options', label: 'Options', type: 'text', optional: true, description: 'Regex options (e.g., "i" for case-insensitivity).' }
|
|
503
|
+
]
|
|
504
|
+
},
|
|
505
|
+
|
|
506
|
+
$text: {
|
|
507
|
+
label: 'Text Search',
|
|
508
|
+
description: 'Performs a full-text search on the collection. Must be a top-level filter condition.',
|
|
509
|
+
isQueryOperator: true,
|
|
510
|
+
isTopLevel: true, // Indicates it's a key in the root of the filter, not under a field name.
|
|
511
|
+
specialStructure: true,
|
|
512
|
+
args: [
|
|
513
|
+
{ name: '$search', label: 'Search Terms', type: 'text' },
|
|
514
|
+
{ name: '$language', label: 'Language', type: 'text', optional: true },
|
|
515
|
+
{ name: '$caseSensitive', label: 'Case Sensitive', type: 'boolean', optional: true },
|
|
516
|
+
{ name: '$diacriticSensitive', label: 'Diacritic Sensitive', type: 'boolean', optional: true }
|
|
517
|
+
]
|
|
518
|
+
},
|
|
519
|
+
|
|
520
|
+
$nearSphere: {
|
|
521
|
+
label: 'Near Sphere',
|
|
522
|
+
description: 'Finds documents near a GeoJSON point on a sphere. Applied to a 2dsphere-indexed field.',
|
|
523
|
+
isQueryOperator: true,
|
|
524
|
+
specialStructure: true,
|
|
525
|
+
args: [
|
|
526
|
+
{ name: 'geometry', label: 'Center Point (GeoJSON)', type: 'code', language: 'json', description: 'e.g., { "type": "Point", "coordinates": [ -73.93, 40.82 ] }' },
|
|
527
|
+
{ name: 'maxDistance', label: 'Max Distance (meters)', type: 'number', optional: true },
|
|
528
|
+
{ name: 'minDistance', label: 'Min Distance (meters)', type: 'number', optional: true }
|
|
529
|
+
]
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
$geoWithin: {
|
|
533
|
+
label: 'Geo Within',
|
|
534
|
+
description: 'Selects documents with geospatial data that exists entirely within a specified shape.',
|
|
535
|
+
isQueryOperator: true,
|
|
536
|
+
specialStructure: true,
|
|
537
|
+
args: [
|
|
538
|
+
{ name: '$geometry', label: 'Shape (GeoJSON)', type: 'code', language: 'json', description: 'A GeoJSON Polygon or MultiPolygon.' }
|
|
539
|
+
]
|
|
540
|
+
},
|
|
541
|
+
|
|
542
|
+
$geoIntersects: {
|
|
543
|
+
label: 'Geo Intersects',
|
|
544
|
+
description: 'Selects documents whose geospatial data intersects with a specified GeoJSON object.',
|
|
545
|
+
isQueryOperator: true,
|
|
546
|
+
specialStructure: true,
|
|
547
|
+
args: [
|
|
548
|
+
{ name: '$geometry', label: 'Geometry (GeoJSON)', type: 'code', language: 'json', description: 'A GeoJSON object to test for intersection.' }
|
|
549
|
+
]
|
|
550
|
+
},
|
|
551
|
+
|
|
552
|
+
// This represents the $geoNear aggregation stage, which has special placement rules.
|
|
553
|
+
$geoNear: {
|
|
554
|
+
label: 'Geo Near (Stage)',
|
|
555
|
+
description: 'Finds and sorts documents by distance. Must be the first operation in a search.',
|
|
556
|
+
isQueryOperator: true,
|
|
557
|
+
isTopLevel: true, // Indicates it's a key in the root of the filter.
|
|
558
|
+
specialStructure: true,
|
|
559
|
+
args: [
|
|
560
|
+
{ name: 'near', label: 'Near Point (GeoJSON)', type: 'code', language: 'json', description: 'The point to search near.' },
|
|
561
|
+
{ name: 'distanceField', label: 'Distance Field Name', type: 'text', description: 'The output field to store the distance.' },
|
|
562
|
+
{ name: 'spherical', label: 'Spherical', type: 'boolean', optional: true, default: true },
|
|
563
|
+
{ name: 'query', label: 'Additional Query', type: 'code', language: 'json', optional: true, description: 'Filters documents before distance calculation.' },
|
|
564
|
+
{ name: 'maxDistance', label: 'Max Distance (meters)', type: 'number', optional: true }
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
};
|
package/src/core.js
CHANGED
|
@@ -36,7 +36,7 @@ export function escapeHtml(string){
|
|
|
36
36
|
export const isDate = dt => String(new Date(dt)) !== 'Invalid Date'
|
|
37
37
|
|
|
38
38
|
export const safeAssignObject = (obj, key, value) => {
|
|
39
|
-
if( !["__proto__", "constructor"].includes(key)){
|
|
39
|
+
if( !["__proto__", "constructor", "prototype"].includes(key)){
|
|
40
40
|
obj[key] = value;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -351,13 +351,13 @@ export const event_trigger = (name, ...params) => {
|
|
|
351
351
|
};
|
|
352
352
|
export const event_on = (name, callback) => {
|
|
353
353
|
if (!Array.isArray(triggers[name])) {
|
|
354
|
-
triggers
|
|
354
|
+
safeAssignObject(triggers, name, []);
|
|
355
355
|
}
|
|
356
356
|
triggers[name].push({ callback });
|
|
357
357
|
};
|
|
358
358
|
export const event_off = (name, callback) => {
|
|
359
359
|
if (callback && triggers[name]) {
|
|
360
|
-
triggers
|
|
360
|
+
safeAssignObject(triggers, name, triggers[name].filter((f) => f.callback !== callback));
|
|
361
361
|
} else {
|
|
362
362
|
triggers[name] = undefined;
|
|
363
363
|
}
|
|
@@ -418,3 +418,21 @@ export function object_equals( x, y ) {
|
|
|
418
418
|
export const isValidPath = (path) =>{
|
|
419
419
|
return /^(?:[a-z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+$/gmi.test(path);
|
|
420
420
|
}
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Génère une couleur de base cohérente à partir d'une chaîne de caractères.
|
|
425
|
+
* @param {string} str La chaîne à hasher (par exemple, le libellé d'une catégorie).
|
|
426
|
+
* @returns {string} Une couleur au format 'hsl(h, s, l)'.
|
|
427
|
+
*/
|
|
428
|
+
export const stringToHslColor = (str) => {
|
|
429
|
+
let hash = 0;
|
|
430
|
+
for (let i = 0; i < str.length; i++) {
|
|
431
|
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
432
|
+
}
|
|
433
|
+
// Utiliser HSL pour un meilleur contrôle sur la saturation et la luminosité
|
|
434
|
+
const h = hash % 360; // Teinte (0-359)
|
|
435
|
+
const s = 70; // Saturation (fixe pour des couleurs vives mais pas criardes)
|
|
436
|
+
const l = 55; // Luminosité (fixe pour une bonne lisibilité)
|
|
437
|
+
return `hsl(${h}, ${s}%, ${l}%)`;
|
|
438
|
+
};
|
package/src/defaultModels.js
CHANGED
|
@@ -1486,6 +1486,12 @@ export const defaultModels = {
|
|
|
1486
1486
|
"icon": "FaCode",
|
|
1487
1487
|
description: "Defines custom API endpoints that execute a server-side script.",
|
|
1488
1488
|
fields: [
|
|
1489
|
+
{
|
|
1490
|
+
name: "isActive",
|
|
1491
|
+
type: "boolean",
|
|
1492
|
+
default: true,
|
|
1493
|
+
hint: "If checked, the endpoint is active and can be called."
|
|
1494
|
+
},
|
|
1489
1495
|
{
|
|
1490
1496
|
name: "name",
|
|
1491
1497
|
type: "string",
|
|
@@ -1493,12 +1499,6 @@ export const defaultModels = {
|
|
|
1493
1499
|
asMain: true,
|
|
1494
1500
|
hint: "A human-readable name to identify the endpoint."
|
|
1495
1501
|
},
|
|
1496
|
-
{
|
|
1497
|
-
name: "isActive",
|
|
1498
|
-
type: "boolean",
|
|
1499
|
-
default: true,
|
|
1500
|
-
hint: "If checked, the endpoint is active and can be called."
|
|
1501
|
-
},
|
|
1502
1502
|
{
|
|
1503
1503
|
name: "path",
|
|
1504
1504
|
type: "string",
|
|
@@ -1514,12 +1514,6 @@ export const defaultModels = {
|
|
|
1514
1514
|
default: "POST",
|
|
1515
1515
|
hint: "The HTTP method required to call this endpoint."
|
|
1516
1516
|
},
|
|
1517
|
-
{
|
|
1518
|
-
name: 'isPublic',
|
|
1519
|
-
type: 'boolean',
|
|
1520
|
-
default: false,
|
|
1521
|
-
hint: "Si coché, ce point d'accès sera accessible sans authentification."
|
|
1522
|
-
},
|
|
1523
1517
|
{
|
|
1524
1518
|
name: "code",
|
|
1525
1519
|
type: "code",
|
|
@@ -1534,6 +1528,12 @@ logger.info('Custom endpoint executed with body:', request.body);
|
|
|
1534
1528
|
|
|
1535
1529
|
return { success: true, message: 'Endpoint executed!', received: request.body };
|
|
1536
1530
|
`
|
|
1531
|
+
},
|
|
1532
|
+
{
|
|
1533
|
+
name: 'isPublic',
|
|
1534
|
+
type: 'boolean',
|
|
1535
|
+
default: false,
|
|
1536
|
+
hint: "Si coché, ce point d'accès sera accessible sans authentification."
|
|
1537
1537
|
}
|
|
1538
1538
|
]
|
|
1539
1539
|
}
|
package/src/engine.js
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
import http from "http";
|
|
14
14
|
import cookieParser from "cookie-parser";
|
|
15
15
|
import requestIp from 'request-ip';
|
|
16
|
-
import {createModel, deleteModels, getModels, installAllPacks, validateModelStructure} from "./modules/data/data.js";
|
|
17
16
|
import {defaultModels} from "./defaultModels.js";
|
|
18
17
|
import {DefaultUserProvider} from "./providers.js";
|
|
19
18
|
import formidableMiddleware from 'express-formidable';
|
|
@@ -22,6 +21,10 @@ import * as tls from "node:tls";
|
|
|
22
21
|
import {Event} from "./events.js";
|
|
23
22
|
import path from "node:path";
|
|
24
23
|
import { fileURLToPath } from 'node:url';
|
|
24
|
+
import {validateModelStructure} from "./modules/data/data.validation.js";
|
|
25
|
+
import { setSafeRegex } from "./filter.js";
|
|
26
|
+
import safeRegexCallback from "safe-regex";
|
|
27
|
+
import {createModel, deleteModels, getModels, installAllPacks} from "./modules/data/data.operations.js";
|
|
25
28
|
// Constants
|
|
26
29
|
|
|
27
30
|
// On définit __dirname pour obtenir le chemin absolu du répertoire courant,
|
|
@@ -96,6 +99,9 @@ export const MongoDatabase = MongoClient.db(dbName);
|
|
|
96
99
|
|
|
97
100
|
export const Engine = {
|
|
98
101
|
Create: async (options = { app : null}) => {
|
|
102
|
+
// On injecte la dépendance safe-regex dans le module de filtrage au tout début.
|
|
103
|
+
setSafeRegex(safeRegexCallback);
|
|
104
|
+
|
|
99
105
|
const engine = GameObject.Create("Engine");
|
|
100
106
|
console.log("Creating engine", Config.Get('modules'));
|
|
101
107
|
const logger = engine.addComponent(Logger);
|
package/src/events.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {safeAssignObject} from "./core.js";
|
|
1
2
|
|
|
2
3
|
const events = {};
|
|
3
4
|
|
|
@@ -81,9 +82,9 @@ export const Event = {
|
|
|
81
82
|
throw new Error(`Layer '${layer}' does not exist in system '${system}'. Valid layers are: ${validLayers.join(', ')}`); // Message d'erreur plus informatif
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
events
|
|
85
|
-
events[system]
|
|
86
|
-
events[system][name]
|
|
85
|
+
safeAssignObject(events, system, events[system] || {}); // Simplification de la création des objets
|
|
86
|
+
safeAssignObject(events[system], name, events[system][name] || {});
|
|
87
|
+
safeAssignObject(events[system][name], layer, events[system][name][layer] || []);
|
|
87
88
|
events[system][name][layer].push(callback);
|
|
88
89
|
},
|
|
89
90
|
RemoveCallback: (name, callback, layer="medium", system='priority') => {
|