data-primals-engine 1.0.6 → 1.0.8
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/package.json +1 -1
- package/server.js +11 -2
- package/src/constants.js +1 -79
- package/src/data.js +15 -5
- package/src/defaultModels.js +125 -13
- package/src/email.js +2 -0
- package/src/engine.js +47 -49
- package/src/gameObject.js +5 -7
- package/src/i18n.js +4153 -62
- package/src/modules/data.js +75 -58
- package/src/modules/mongodb.js +1 -1
- package/src/modules/workflow.js +190 -58
- package/src/packs.js +26 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "data-primals-engine is the package responsible from handling large amount of data in a practical and performant way. It can handle large amount of data in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation.",
|
|
5
5
|
"main": "src/engine.js",
|
|
6
6
|
"type": "module",
|
package/server.js
CHANGED
|
@@ -13,11 +13,20 @@ const bench = GameObject.Create("Benchmark");
|
|
|
13
13
|
const timer = bench.addComponent(BenchmarkTool);
|
|
14
14
|
timer.start();
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
const engine = await Engine.Create();
|
|
18
|
+
|
|
19
|
+
if (process.argv.length === 3) {
|
|
20
|
+
let arg = process.argv[2];
|
|
21
|
+
if( arg === 'reset-models'){
|
|
22
|
+
console.log("resetting models");
|
|
23
|
+
await engine.resetModels();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
17
26
|
|
|
18
27
|
const port = process.env.PORT || 7633;
|
|
19
28
|
engine.start(port, async (r) => {
|
|
20
29
|
const logger = engine.getComponent(Logger);
|
|
21
|
-
|
|
30
|
+
console.log("Server started on port" + port);
|
|
22
31
|
timer.stop();
|
|
23
32
|
});
|
package/src/constants.js
CHANGED
|
@@ -2,24 +2,6 @@ export const dbName = "engine";
|
|
|
2
2
|
|
|
3
3
|
export const cookiesSecret = 'hoaivuymzovyoznllmafivpzaovphlejvalwjvelfhqochakfesv';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
export const langs = {
|
|
7
|
-
fr: "Français",
|
|
8
|
-
en: "English",
|
|
9
|
-
ar: "عربي",
|
|
10
|
-
fa: "فارسی",
|
|
11
|
-
it: "Italiano",
|
|
12
|
-
es: "Español",
|
|
13
|
-
el: "Ελληνικά",
|
|
14
|
-
de: "Deutsch",
|
|
15
|
-
cs: "Čeština",
|
|
16
|
-
sv: "Svenska",
|
|
17
|
-
pt: "Português",
|
|
18
|
-
ja: "日本語",
|
|
19
|
-
zh: "简体中文",
|
|
20
|
-
ru: "Русский",
|
|
21
|
-
};
|
|
22
|
-
|
|
23
5
|
export const availableLangs = [
|
|
24
6
|
"en",
|
|
25
7
|
"fa",
|
|
@@ -138,7 +120,7 @@ metaModels['common'] = { load: ['contact', 'location', 'request'] };
|
|
|
138
120
|
metaModels['personal'] = { load: ['budget', 'imageGallery'] };
|
|
139
121
|
metaModels['users'] = { load: ['permission', 'role', 'user', 'token'], 'require': ['i18n', 'common'] };
|
|
140
122
|
metaModels['i18n'] = { load: ['translation','lang']};
|
|
141
|
-
metaModels['website'] = { load: ['webpage', 'content', 'taxonomy', 'contact', 'resource'], 'require': ['i18n'] };
|
|
123
|
+
metaModels['website'] = { load: ['webpage', 'content', 'taxonomy', 'contact', 'event', 'resource'], 'require': ['i18n'] };
|
|
142
124
|
metaModels['messaging'] = { load: ['alert','ticket', 'message', 'channel'], 'require': ['i18n'] };
|
|
143
125
|
metaModels['eshopping'] = { load: [
|
|
144
126
|
'order', 'currency', 'product', 'productVariant', 'discount', 'cart', 'cartItem',
|
|
@@ -148,67 +130,7 @@ metaModels['eshopping'] = { load: [
|
|
|
148
130
|
metaModels['workflow'] = { load: ['env', 'workflow', 'workflowRun', 'workflowAction', 'workflowStep', 'workflowTrigger']};
|
|
149
131
|
metaModels['erp'] = { load: [ 'accountingExercise', 'accountingLineItem', 'accountingEntry', 'employee', 'dashboard', 'kpi'] };
|
|
150
132
|
|
|
151
|
-
export const profiles = {
|
|
152
|
-
'personal': ['contact', 'location', 'imageGallery', 'budget', 'currency', 'taxonomy'], // budget,
|
|
153
|
-
'developer': ['alert','request','webpage', 'content', 'taxonomy', 'resource', 'translation', 'contact', 'location', 'channel', 'lang', 'token', 'message', 'ticket', 'user', 'permission', 'role'],
|
|
154
|
-
'company': ['alert','request','location', 'campaign', 'order', 'currency', 'product', 'cart', 'cartItem', 'invoice', 'messaging', 'user', 'role', 'permission', 'token','translation', 'lang', 'webpage', 'content', 'taxonomy', 'contact', 'resource', 'accountingExercise', 'accountingLineItem', 'accountingEntry', 'employee', 'kpi', 'dashboard'],
|
|
155
|
-
'engineer': ['alert','request','dashboard', 'kpi', 'user', 'role', 'token', 'permission', 'workflow', 'workflowRun', 'workflowStep', "channel", "message", 'workflowAction', 'workflowTrigger']
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Dans ConditionBuilder.jsx ou un fichier de constantes partagé
|
|
159
|
-
export const mongoOperators = [
|
|
160
|
-
{ value: '$eq', label: '==', inputType: 'text' }, // Égal (pour string, number, boolean...)
|
|
161
|
-
{ value: '$ne', label: '!=', inputType: 'text' }, // Différent
|
|
162
|
-
{ value: '$gt', label: '>', inputType: 'number' }, // Supérieur (nombre, date)
|
|
163
|
-
{ value: '$gte', label: '>=', inputType: 'number' }, // Supérieur ou égal à
|
|
164
|
-
{ value: '$lt', label: '<', inputType: 'number' }, // Inférieur à
|
|
165
|
-
{ value: '$lte', label: '<=', inputType: 'number' }, // Inférieur ou égal à
|
|
166
|
-
{ value: '$regex', label: 'contient (regex)', inputType: 'text' }, // Correspondance Regex (pour string)
|
|
167
|
-
{ value: '$in', label: 'est dans (liste)', inputType: 'csv' }, // Dans un tableau (valeurs séparées par des virgules)
|
|
168
|
-
{ value: '$nin', label: "n'est pas dans (liste)", inputType: 'csv' }, // Pas dans un tableau
|
|
169
|
-
{ value: '$exists', label: 'existe', inputType: 'boolean' }, // Le champ existe (true/false)
|
|
170
|
-
// { value: '$not', label: 'NON (condition)', inputType: 'condition' }, // Pourrait encapsuler une autre condition
|
|
171
|
-
// Ajoutez d'autres opérateurs MongoDB pertinents si besoin ($size, $type, $elemMatch...)
|
|
172
|
-
];
|
|
173
133
|
|
|
174
134
|
export const allowedFields = ['locked', 'hiddenable', 'anonymized', 'condition', 'color', 'index', 'type', 'required', 'hint', 'default', 'validate', 'unique', 'name', 'placeholder', 'asMain'];
|
|
175
135
|
|
|
176
136
|
|
|
177
|
-
|
|
178
|
-
export const MONGO_OPERATORS = {
|
|
179
|
-
ADD: { mongo: '$add', label: '+', type: 'numeric', multi: true },
|
|
180
|
-
SUBTRACT: { mongo: '$subtract', label: '-', type: 'numeric', multi: false },
|
|
181
|
-
MULTIPLY: { mongo: '$multiply', label: '*', type: 'numeric', multi: true },
|
|
182
|
-
DIVIDE: { mongo: '$divide', label: '/', type: 'numeric', multi: false },
|
|
183
|
-
MODULO: { mongo: '$mod', label: '%', type: 'numeric', multi: false },
|
|
184
|
-
POW: { mongo: '$pow', label: 'pow', type: 'numeric', multi: false },
|
|
185
|
-
SQRT: { mongo: '$sqrt', label: '√', type: 'numeric', multi: false, unary: true },
|
|
186
|
-
ABS: { mongo: '$abs', label: 'abs', type: 'numeric', multi: false, unary: true },
|
|
187
|
-
CEIL: { mongo: '$ceil', label: 'ceil', type: 'numeric', multi: false, unary: true },
|
|
188
|
-
FLOOR: { mongo: '$floor', label: 'floor', type: 'numeric', multi: false, unary: true },
|
|
189
|
-
COS: { mongo: '$cos', label: 'cos', type: 'numeric', multi: false, unary: true },
|
|
190
|
-
ACOS: { mongo: '$acos', label: 'acos', type: 'numeric', multi: false, unary: true },
|
|
191
|
-
SIN: { mongo: '$sin', label: 'sin', type: 'numeric', multi: false, unary: true },
|
|
192
|
-
ASIN: { mongo: '$asin', label: 'asin', type: 'numeric', multi: false, unary: true },
|
|
193
|
-
TAN: { mongo: '$tan', label: 'tan', type: 'numeric', multi: false, unary: true },
|
|
194
|
-
ATAN: { mongo: '$atan', label: 'atan', type: 'numeric', multi: false, unary: true },
|
|
195
|
-
LN: { mongo: '$ln', label: 'ln', type: 'numeric', multi: false, unary: true },
|
|
196
|
-
LOG: { mongo: '$log10', label: 'log', type: 'numeric', multi: false, unary: true },
|
|
197
|
-
|
|
198
|
-
CONCAT: { mongo: '$concat', label: 'concat', type: 'string', multi: true },
|
|
199
|
-
|
|
200
|
-
YEAR: { mongo: '$year', label: 'year', type: 'date', unary: true },
|
|
201
|
-
MONTH: { mongo: '$month', label: 'month', type: 'date', unary: true },
|
|
202
|
-
WEEK: { mongo: '$week', label: 'week', type: 'date', unary: true },
|
|
203
|
-
DAY_OF_MONTH: { mongo: '$dayOfMonth', label: 'day', type: 'date', unary: true },
|
|
204
|
-
HOUR: { mongo: '$hour', label: 'hour', type: 'date', unary: true },
|
|
205
|
-
MINUTE: { mongo: '$minute', label: 'min', type: 'date', unary: true },
|
|
206
|
-
SECOND: { mongo: '$second', label: 'sec', type: 'date', unary: true },
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
export const OPERAND_TYPES = {
|
|
210
|
-
FIELD: 'field',
|
|
211
|
-
CONSTANT: 'constant',
|
|
212
|
-
PREVIOUS_STEP: 'previousStep',
|
|
213
|
-
};
|
|
214
|
-
|
package/src/data.js
CHANGED
|
@@ -29,8 +29,12 @@ export const isLocalUser = (user) => {
|
|
|
29
29
|
return user && user._model === 'user' && typeof(user._user) === 'string' && user._user.trim() !== '';
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
export const isDemoUser = (user) => {
|
|
33
|
+
return /^demo[0-9]{1,2}$/.test(user?.username);
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
export function getUserHash(user) {
|
|
33
|
-
if(
|
|
37
|
+
if( isDemoUser(user) ){
|
|
34
38
|
return user.username;
|
|
35
39
|
}
|
|
36
40
|
return user ? (
|
|
@@ -419,8 +423,9 @@ export const getFieldValueHash = (model, data) => {
|
|
|
419
423
|
* @param {array} allModels - Un tableau contenant les définitions de TOUS les modèles du système.
|
|
420
424
|
* @returns {string} - La chaîne de caractères représentant la donnée.
|
|
421
425
|
*/
|
|
422
|
-
export const getDataAsString = (model, data,
|
|
423
|
-
|
|
426
|
+
export const getDataAsString = (model, data, tr, allModels, extended=false) => {
|
|
427
|
+
const { t, i18n} = tr;
|
|
428
|
+
const lang = (i18n.resolvedLanguage || i18n.language).split(/[-_]/)?.[0];
|
|
424
429
|
// Cas de base : si le modèle ou les données sont manquants, on ne peut rien faire.
|
|
425
430
|
if (!model || !data) {
|
|
426
431
|
return '';
|
|
@@ -464,7 +469,6 @@ export const getDataAsString = (model, data, t, allModels, extended=false) => {
|
|
|
464
469
|
const relatedModel = allModels?.find(m => m.name === fieldDef.relation);
|
|
465
470
|
if (!relatedModel) return `[${fieldDef.relation}]`; // Modnon trouvé
|
|
466
471
|
|
|
467
|
-
console.log({relatedModel, value});
|
|
468
472
|
// Si la relation est multiple (un tableau d'objets)
|
|
469
473
|
if (Array.isArray(value)) {
|
|
470
474
|
return value
|
|
@@ -474,10 +478,16 @@ export const getDataAsString = (model, data, t, allModels, extended=false) => {
|
|
|
474
478
|
}
|
|
475
479
|
// Si la relation est simple (un seul objet)
|
|
476
480
|
else if (typeof value === 'object') {
|
|
477
|
-
console.log({relatedModel, value});
|
|
478
481
|
return getDataAsString(relatedModel, value, t, allModels); // Appel récursif
|
|
479
482
|
}
|
|
480
483
|
}
|
|
484
|
+
|
|
485
|
+
if(fieldDef.type === 'datetime'){
|
|
486
|
+
return new Date(value).toLocaleDateString(lang, {year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric'});
|
|
487
|
+
}
|
|
488
|
+
if(fieldDef.type === 'date'){
|
|
489
|
+
return new Date(value).toLocaleDateString(lang, {year: 'numeric', month: 'numeric', day: 'numeric'});
|
|
490
|
+
}
|
|
481
491
|
// --- FIN DE LA NOUVELLE LOGIQUE ---
|
|
482
492
|
|
|
483
493
|
// Logique existante pour les autres types de champs
|
package/src/defaultModels.js
CHANGED
|
@@ -106,11 +106,11 @@ export const defaultModels = {
|
|
|
106
106
|
{ name: 'subject', type: 'string' }, // Sujet de la notification (ex: titre de l'email)
|
|
107
107
|
{ name: 'content', type: 'richtext', required: true }, // Contenu du message (localisable)
|
|
108
108
|
{ name: 'channels', type: 'relation', multiple: true, relation: 'channel' }, // Canaux de diffusion (email, SMS, forum, etc.)
|
|
109
|
-
{ name: 'status', type: 'enum', items: ['
|
|
109
|
+
{ name: 'status', type: 'enum', items: ['pending', 'sent', 'read', 'failed'] },
|
|
110
110
|
{ name: 'sentAt', type: 'datetime' },
|
|
111
111
|
{ name: 'readAt', type: 'datetime' },
|
|
112
112
|
{ name: 'type', type: 'string' }, // Type de notification (ex: "commande.miseAJour", "messageForum")
|
|
113
|
-
{ name: 'priority', type: 'enum', items: ['
|
|
113
|
+
{ name: 'priority', type: 'enum', items: ['low', 'medium', 'high']},
|
|
114
114
|
],
|
|
115
115
|
},
|
|
116
116
|
alert: {
|
|
@@ -404,7 +404,7 @@ export const defaultModels = {
|
|
|
404
404
|
{ name: 'invoiceId', type: 'string', required: true, unique: true },
|
|
405
405
|
{ name: 'invoiceDate', type: 'datetime', required: true },
|
|
406
406
|
{ name: 'dueDate', type: 'datetime' },
|
|
407
|
-
{ name: 'status', type: 'enum', items: ['
|
|
407
|
+
{ name: 'status', type: 'enum', items: ['paid', 'unpaid', 'partially_paid', 'cancelled'] },
|
|
408
408
|
],
|
|
409
409
|
},
|
|
410
410
|
userSubscription: {
|
|
@@ -418,8 +418,8 @@ export const defaultModels = {
|
|
|
418
418
|
{ name: 'endDate', type: 'datetime' },
|
|
419
419
|
{ name: 'price', type: 'number', required: true },
|
|
420
420
|
{ name: 'currency', type: 'relation', relation: 'currency', required: true },
|
|
421
|
-
{ name: 'paymentMethod', type: 'enum', items: ['
|
|
422
|
-
{ name: 'status', type: 'enum', items: ['
|
|
421
|
+
{ name: 'paymentMethod', type: 'enum', items: ['bank_card', 'SEPA_mandate', 'cash', 'check', 'other'] },
|
|
422
|
+
{ name: 'status', type: 'enum', items: ['active', 'inactive', 'cancelled', 'expired', 'pending'] },
|
|
423
423
|
{ name: 'billingCycleAnchor', type: 'datetime' },
|
|
424
424
|
{ name: 'nextBillingDate', type: 'datetime' },
|
|
425
425
|
{ name: 'lastBillingDate', type: 'datetime' },
|
|
@@ -455,7 +455,7 @@ export const defaultModels = {
|
|
|
455
455
|
{ name: 'order', type: 'relation', relation: 'order', required: true },
|
|
456
456
|
{ name: 'trackingNumber', type: 'string' },
|
|
457
457
|
{ name: 'carrier', type: 'string' },
|
|
458
|
-
{ name: 'status', type: 'enum', items: ['
|
|
458
|
+
{ name: 'status', type: 'enum', items: ['pending', 'in_transit', 'delivered', 'issue'] },
|
|
459
459
|
{ name: 'estimatedDeliveryDate', type: 'datetime' },
|
|
460
460
|
{ name: 'actualDeliveryDate', type: 'datetime' }
|
|
461
461
|
],
|
|
@@ -476,7 +476,7 @@ export const defaultModels = {
|
|
|
476
476
|
{ "name": "user", "type": "relation", relation: "user" },
|
|
477
477
|
{ "name": "reason", "type": "string", maxlength: 2048, required: true },
|
|
478
478
|
{ "name": "channel", "type": "relation", relation: 'channel' },
|
|
479
|
-
{ "name": "status", "type": "enum", items: ["
|
|
479
|
+
{ "name": "status", "type": "enum", items: ["pending", "approved", "refunded", "refused"] },
|
|
480
480
|
{ name: 'amount', type: 'number', min: 0 },
|
|
481
481
|
{ name: 'currency', type: 'relation', relation: 'currency' },
|
|
482
482
|
{ name: 'refundDate', type: 'datetime' },
|
|
@@ -490,7 +490,7 @@ export const defaultModels = {
|
|
|
490
490
|
{ name: 'product', type: 'relation', relation: 'product', required: true },
|
|
491
491
|
{ name: 'variant', type: 'relation', relation: 'productVariant' },
|
|
492
492
|
{ name: 'quantity', type: 'number', required: true, min: 1 },
|
|
493
|
-
{ name: 'condition', type: 'enum', items: ['
|
|
493
|
+
{ name: 'condition', type: 'enum', items: ['new', 'very_good', 'good', 'degraded', 'damaged', 'unusable'] }
|
|
494
494
|
],
|
|
495
495
|
},
|
|
496
496
|
ticket: {
|
|
@@ -504,8 +504,8 @@ export const defaultModels = {
|
|
|
504
504
|
{ name: 'parent', type: 'relation', relation: 'ticket' },
|
|
505
505
|
{ name: 'subject', type: 'string', required: true },
|
|
506
506
|
{ name: 'message', type: 'richtext', required: true },
|
|
507
|
-
{ name: 'status', type: 'enum', items: ['
|
|
508
|
-
{ name: 'priority', type: 'enum', items: ['
|
|
507
|
+
{ name: 'status', type: 'enum', items: ['opened', 'in_progress', 'closed'] },
|
|
508
|
+
{ name: 'priority', type: 'enum', items: ['low', 'medium', 'high', 'urgent'] },
|
|
509
509
|
{ name: 'assignedTo', type: 'relation', relation: 'user' },
|
|
510
510
|
{ name: 'createdAt', type: 'datetime', required: true }
|
|
511
511
|
],
|
|
@@ -518,8 +518,8 @@ export const defaultModels = {
|
|
|
518
518
|
{ name: 'description', type: 'richtext' },
|
|
519
519
|
{ name: 'startDate', type: 'datetime' },
|
|
520
520
|
{ name: 'endDate', type: 'datetime' },
|
|
521
|
-
{ name: 'type', type: 'enum', items: ['email', '
|
|
522
|
-
{ name: 'status', type: 'enum', items: ['
|
|
521
|
+
{ name: 'type', type: 'enum', items: ['email', 'sms', 'advertisement', 'promotion'] },
|
|
522
|
+
{ name: 'status', type: 'enum', items: ['planified', 'in_progress', 'finished', 'cancelled'] },
|
|
523
523
|
{ name: 'budget', type: 'number' }
|
|
524
524
|
],
|
|
525
525
|
},
|
|
@@ -631,7 +631,7 @@ export const defaultModels = {
|
|
|
631
631
|
{
|
|
632
632
|
"name": "status",
|
|
633
633
|
"type": "enum",
|
|
634
|
-
"items": ["
|
|
634
|
+
"items": ["draft", "validated", "cancelled"],
|
|
635
635
|
"default": "brouillon"
|
|
636
636
|
},
|
|
637
637
|
{
|
|
@@ -1283,5 +1283,117 @@ export const defaultModels = {
|
|
|
1283
1283
|
hint: "Pièces jointes (reçus, factures)."
|
|
1284
1284
|
},
|
|
1285
1285
|
]
|
|
1286
|
+
},
|
|
1287
|
+
event: {
|
|
1288
|
+
"name": "event",
|
|
1289
|
+
"description": "A model for managing events, conferences, meetups, and gatherings.",
|
|
1290
|
+
"fields": [
|
|
1291
|
+
{
|
|
1292
|
+
"name": "title",
|
|
1293
|
+
"type": "string",
|
|
1294
|
+
"required": true,
|
|
1295
|
+
"asMain": true,
|
|
1296
|
+
"hint": "The title of the event"
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
"name": "description",
|
|
1300
|
+
"type": "richtext_t",
|
|
1301
|
+
"hint": "A detailed description of the event, including agenda, speakers, and other relevant information."
|
|
1302
|
+
},
|
|
1303
|
+
{
|
|
1304
|
+
"name": "startDate",
|
|
1305
|
+
"type": "datetime",
|
|
1306
|
+
"required": true,
|
|
1307
|
+
"hint": "The starting date and time of the event"
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
"name": "endDate",
|
|
1311
|
+
"type": "datetime",
|
|
1312
|
+
"required": true,
|
|
1313
|
+
"hint": "The ending date and time of the event"
|
|
1314
|
+
},
|
|
1315
|
+
{
|
|
1316
|
+
"name": "location",
|
|
1317
|
+
"type": "relation",
|
|
1318
|
+
"relation": "location",
|
|
1319
|
+
"hint": "The venue or location where the event will be held. This could be a physical address or an online meeting link."
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
"name": "categories",
|
|
1323
|
+
"type": "relation",
|
|
1324
|
+
"relation": "taxonomy",
|
|
1325
|
+
"multiple": true,
|
|
1326
|
+
"hint": "Categories or tags associated with the event (e.g., \"conference\", \"workshop\", \"music\", \"technology\")."
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
"name": "organizer",
|
|
1330
|
+
"type": "relation",
|
|
1331
|
+
"relation": "contact",
|
|
1332
|
+
"hint": "The name of the organization or individual hosting the event."
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
"name": "isOnline",
|
|
1336
|
+
"type": "boolean",
|
|
1337
|
+
"default": false,
|
|
1338
|
+
"hint": "Whether the event is online or in-person."
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
"name": "eventUrl",
|
|
1342
|
+
"type": "url",
|
|
1343
|
+
"hint": "A link to the official event webpage or registration page."
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
"name": "imageUrl",
|
|
1347
|
+
"type": "file",
|
|
1348
|
+
"hint": "URL of the event image or banner."
|
|
1349
|
+
},
|
|
1350
|
+
{
|
|
1351
|
+
"name": "status",
|
|
1352
|
+
"type": "enum",
|
|
1353
|
+
"items": [
|
|
1354
|
+
"scheduled",
|
|
1355
|
+
"ongoing",
|
|
1356
|
+
"completed",
|
|
1357
|
+
"cancelled",
|
|
1358
|
+
"postponed"
|
|
1359
|
+
],
|
|
1360
|
+
"hint": "The current status of the event."
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
"name": "capacity",
|
|
1364
|
+
"type": "number",
|
|
1365
|
+
"hint": "The maximum number of attendees allowed for the event."
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
"name": "price",
|
|
1369
|
+
"type": "number",
|
|
1370
|
+
"hint": "The price of admission, if applicable."
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
"name": "currency",
|
|
1374
|
+
"type": "relation",
|
|
1375
|
+
"relation": "currency",
|
|
1376
|
+
"hint": "The currency for the price (e.g., USD, EUR)."
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
"name": "registrationDeadline",
|
|
1380
|
+
"type": "datetime",
|
|
1381
|
+
"hint": "The date by which attendees must register for the event."
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
"name": "attendees",
|
|
1385
|
+
"type": "relation",
|
|
1386
|
+
"relation": "contact",
|
|
1387
|
+
"multiple": true,
|
|
1388
|
+
"hint": "A relation to the contacts attending the event"
|
|
1389
|
+
},
|
|
1390
|
+
{
|
|
1391
|
+
"name": "sponsors",
|
|
1392
|
+
"type": "relation",
|
|
1393
|
+
"relation": "contact",
|
|
1394
|
+
"multiple": true,
|
|
1395
|
+
"hint": "List of sponsors or partners involved in the event."
|
|
1396
|
+
}
|
|
1397
|
+
]
|
|
1286
1398
|
}
|
|
1287
1399
|
};
|
package/src/email.js
CHANGED
|
@@ -2,6 +2,8 @@ import { translations } from "data-primals-engine/i18n";
|
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import nodemailer from "nodemailer";
|
|
4
4
|
import juice from "juice";
|
|
5
|
+
import {event_trigger} from "./core.js";
|
|
6
|
+
import {emailDefaultConfig} from "./constants.js";
|
|
5
7
|
|
|
6
8
|
// Le transporteur par défaut, utilisé si aucune config spécifique n'est fournie.
|
|
7
9
|
const defaultTransporter = nodemailer.createTransport({
|
package/src/engine.js
CHANGED
|
@@ -4,14 +4,11 @@ import fs from 'node:fs'
|
|
|
4
4
|
import express from 'express'
|
|
5
5
|
import {MongoClient as InternalMongoClient} from 'mongodb'
|
|
6
6
|
import process from "process";
|
|
7
|
-
import
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
import bodyParser from "body-parser";
|
|
10
|
-
import {cookiesSecret, dbName, install, maxDataSize} from "./constants.js";
|
|
7
|
+
import {cookiesSecret, dbName} from "./constants.js";
|
|
11
8
|
import http from "http";
|
|
12
9
|
import cookieParser from "cookie-parser";
|
|
13
10
|
import requestIp from 'request-ip';
|
|
14
|
-
import {createModel,
|
|
11
|
+
import {createModel, deleteModels, getModels, validateModelStructure} from "./modules/data.js";
|
|
15
12
|
import {defaultModels} from "./defaultModels.js";
|
|
16
13
|
import {DefaultUserProvider} from "./providers.js";
|
|
17
14
|
import formidableMiddleware from 'express-formidable';
|
|
@@ -28,9 +25,10 @@ export const MongoDatabase = MongoClient.db(dbName);
|
|
|
28
25
|
|
|
29
26
|
|
|
30
27
|
export const Engine = {
|
|
31
|
-
Create:
|
|
28
|
+
Create: async (options) => {
|
|
32
29
|
const engine = GameObject.Create("Engine");
|
|
33
30
|
console.log("Creating engine", Config.Get('modules'));
|
|
31
|
+
engine.addComponent(Logger);
|
|
34
32
|
|
|
35
33
|
engine.userProvider = new DefaultUserProvider(engine);
|
|
36
34
|
|
|
@@ -39,9 +37,8 @@ export const Engine = {
|
|
|
39
37
|
engine.getComponent(Logger).info(`Custom UserProvider '${providerInstance.constructor.name}' has been set.`);
|
|
40
38
|
};
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Allows you to set port in the project properties.
|
|
40
|
+
const app = express();
|
|
41
|
+
// Allows you to set port in the project properties.
|
|
45
42
|
app.set('port', process.env.PORT || 3000);
|
|
46
43
|
app.set('engine', engine);
|
|
47
44
|
|
|
@@ -50,7 +47,7 @@ export const Engine = {
|
|
|
50
47
|
uploadDir: process.cwd()+'/uploads/tmp',
|
|
51
48
|
multiples: true, // req.files to be arrays of files
|
|
52
49
|
}));
|
|
53
|
-
app.use(cookieParser(
|
|
50
|
+
app.use(cookieParser(process.env.COOKIES_SECRET || cookiesSecret));
|
|
54
51
|
app.use(requestIp.mw())
|
|
55
52
|
|
|
56
53
|
engine.use = (...args) => {
|
|
@@ -75,10 +72,38 @@ export const Engine = {
|
|
|
75
72
|
return engine._modules.find(m => m.module === module);
|
|
76
73
|
};
|
|
77
74
|
|
|
75
|
+
|
|
76
|
+
const logger = engine.getComponent(Logger);
|
|
77
|
+
|
|
78
|
+
const importModule = async (module) => {
|
|
79
|
+
const moduleA = await import(module);
|
|
80
|
+
if (moduleA.onInit){
|
|
81
|
+
await moduleA.onInit(engine);
|
|
82
|
+
return {...moduleA, module};
|
|
83
|
+
}else {
|
|
84
|
+
const mod = moduleA.default();
|
|
85
|
+
await mod?.onInit(engine);
|
|
86
|
+
return { ...mod, module};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
await Promise.all(Config.Get('modules').map(async module => {
|
|
91
|
+
try {
|
|
92
|
+
if( fs.existsSync(module)){
|
|
93
|
+
return await importModule(module);
|
|
94
|
+
}else {
|
|
95
|
+
return await importModule('./modules/' + module + ".js");
|
|
96
|
+
}
|
|
97
|
+
} catch (e){
|
|
98
|
+
console.log('ERROR at loading module '+ module + ' in /modules dir.'+ e);
|
|
99
|
+
}
|
|
100
|
+
})).then(async e => {
|
|
101
|
+
engine._modules = e;
|
|
102
|
+
return Promise.resolve();
|
|
103
|
+
});
|
|
78
104
|
let server;
|
|
79
105
|
engine.start = async (port, cb) =>{
|
|
80
106
|
// Use connect method to connect to the server
|
|
81
|
-
await MongoClient.connect();
|
|
82
107
|
|
|
83
108
|
// Start http server
|
|
84
109
|
server = http.createServer(app);
|
|
@@ -91,37 +116,11 @@ export const Engine = {
|
|
|
91
116
|
|
|
92
117
|
server.listen(port);
|
|
93
118
|
|
|
94
|
-
const importModule = async (module) => {
|
|
95
|
-
const moduleA = await import(module);
|
|
96
|
-
if (moduleA.onInit){
|
|
97
|
-
await moduleA.onInit(engine);
|
|
98
|
-
return {...moduleA, module};
|
|
99
|
-
}else {
|
|
100
|
-
const mod = moduleA.default();
|
|
101
|
-
await mod?.onInit(engine);
|
|
102
|
-
return { ...mod, module};
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
await Promise.all(Config.Get('modules').map(async module => {
|
|
107
|
-
try {
|
|
108
|
-
if( fs.existsSync(module)){
|
|
109
|
-
return await importModule(module);
|
|
110
|
-
}else {
|
|
111
|
-
return await importModule('./modules/' + module + ".js");
|
|
112
|
-
}
|
|
113
|
-
} catch (e){
|
|
114
|
-
console.log('ERROR at loading module '+ module + ' in /modules dir.'+ e);
|
|
115
|
-
}
|
|
116
|
-
})).then(async e => {
|
|
117
|
-
engine._modules = e;
|
|
118
|
-
if (cb)
|
|
119
|
-
return await cb();
|
|
120
|
-
return Promise.resolve();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
119
|
await setupInitialModels();
|
|
124
120
|
|
|
121
|
+
if (cb)
|
|
122
|
+
await cb();
|
|
123
|
+
|
|
125
124
|
process.on('uncaughtException', function (exception) {
|
|
126
125
|
console.error(exception);
|
|
127
126
|
fs.appendFile('issues.txt', JSON.stringify({ code: exception.code, message: exception.message, stack: exception.stack }), function (err) {
|
|
@@ -132,17 +131,14 @@ export const Engine = {
|
|
|
132
131
|
process.exit(0);
|
|
133
132
|
});
|
|
134
133
|
}
|
|
135
|
-
engine.addComponent(Logger);
|
|
136
134
|
|
|
137
135
|
engine.stop = async () => {
|
|
138
136
|
await server.close();
|
|
139
137
|
};
|
|
140
138
|
|
|
141
|
-
const logger = engine.getComponent(Logger);
|
|
142
|
-
|
|
143
139
|
async function setupInitialModels() {
|
|
144
|
-
logger.info("
|
|
145
|
-
const ms = Object.values(Config.Get('defaultModels',
|
|
140
|
+
logger.info("Validating structures of default models...");
|
|
141
|
+
const ms = Object.values(Config.Get('defaultModels', defaultModels));
|
|
146
142
|
|
|
147
143
|
let dbModels = await getModels();
|
|
148
144
|
|
|
@@ -155,13 +151,15 @@ export const Engine = {
|
|
|
155
151
|
model.locked = true;
|
|
156
152
|
const r = await createModel(model);
|
|
157
153
|
dbModels.push({...model, _id: r.insertedId });
|
|
158
|
-
|
|
159
|
-
else
|
|
160
|
-
|
|
154
|
+
logger.info('Model inserted (' + model.name + ')');
|
|
155
|
+
}else
|
|
156
|
+
logger.info('Model loaded (' + model.name + ')');
|
|
161
157
|
}
|
|
162
158
|
logger.info("All models loaded.");
|
|
163
159
|
}
|
|
164
|
-
|
|
160
|
+
engine.resetModels = async () => {
|
|
161
|
+
await deleteModels();
|
|
162
|
+
};
|
|
165
163
|
return engine;
|
|
166
164
|
}
|
|
167
165
|
}
|
package/src/gameObject.js
CHANGED
|
@@ -70,23 +70,21 @@ export class UsableBehaviour extends Behaviour {
|
|
|
70
70
|
|
|
71
71
|
use() {
|
|
72
72
|
Event.Trigger("GameObject.UsableBehavior.use", "system", "calls", this);
|
|
73
|
-
// Logique d'utilisation (exemple)
|
|
74
|
-
console.log(this.gameObject.name + " a été utilisé !");
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
const
|
|
76
|
+
const mainDriver = GameObject.Create("MainDrivers");
|
|
79
77
|
|
|
80
78
|
// Exemple d'attachement de comportements
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
mainDriver.addComponent(MovableBehaviour, 10);
|
|
80
|
+
mainDriver.addComponent(UsableBehaviour);
|
|
83
81
|
|
|
84
82
|
// Accéder et utiliser les composants
|
|
85
|
-
const movable =
|
|
83
|
+
const movable = mainDriver.getComponent(MovableBehaviour);
|
|
86
84
|
if (movable) {
|
|
87
85
|
movable.update();
|
|
88
86
|
}
|
|
89
|
-
const usable =
|
|
87
|
+
const usable = mainDriver.getComponent(UsableBehaviour);
|
|
90
88
|
if (usable) {
|
|
91
89
|
usable.use();
|
|
92
90
|
}
|