data-primals-engine 1.1.4 → 1.1.6

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.
@@ -7,6 +7,12 @@ export const MONGO_CALC_OPERATORS = {
7
7
  multi: false,
8
8
  isFindOperator: true // Nouvelle propriété pour identifier les opérateurs $find
9
9
  },
10
+ '$regexMatch': {
11
+ label: 'Find by regex',
12
+ description: 'Find a string matching a regular expression (Ecmascript)',
13
+ args: 2, // input et regex
14
+ specialStructure: true // Indique une structure spéciale
15
+ },
10
16
  $and: { label: 'Et (and)', description: 'Renvoie vrai si toutes les conditions sont vérifiées', args: 1, multi: true },
11
17
  $or: { label: 'Ou (or)', description: 'Renvoie vrai si au moins une des conditions est vérifiée.', args: 1, multi: true },
12
18
  $not: { label: 'Non (not)', description: 'Inverse la condition (ex: non égal à).', args: 1, multi: true },
@@ -57,7 +63,7 @@ export const MONGO_CALC_OPERATORS = {
57
63
  $toBool: { label: 'toBool', multi: false, converter: true },
58
64
  $toString: { label: 'toString', multi: false, converter: true },
59
65
  $toInt: { label: 'toInt', multi: false, converter: true },
60
- $toDouble: { label: 'toDouble', multi: false, converter: true },
66
+ $toDouble: { label: 'toDouble', multi: false, converter: true }
61
67
  };
62
68
 
63
69
  export const convertInputValue = (value) => {
@@ -219,4 +225,37 @@ export const buildRootFromExpr = (query) => {
219
225
  if (parsedRoot.$and || parsedRoot.$or) return parsedRoot;
220
226
 
221
227
  return { $and: [parsedRoot] };
228
+ };
229
+
230
+ export const pagedFilterToMongoConds = (pagedFilters, model) => {
231
+ const modelFilter = pagedFilters?.[model.name] || {};
232
+ const filterKeys = Object.keys(modelFilter);
233
+
234
+ // Si le filtre est vide, on retourne un tableau vide.
235
+ if (filterKeys.length === 0) {
236
+ return [];
237
+ }
238
+
239
+ // Détecte si c'est un filtre avancé (contient des opérateurs logiques de haut niveau comme $and, $or, etc.)
240
+ const isAdvancedFilter = filterKeys.some(key => key.startsWith('$'));
241
+
242
+ if (isAdvancedFilter) {
243
+ // C'est un filtre avancé du ConditionBuilder.
244
+ // Il est déjà une condition MongoDB complète. On le met dans un tableau pour l'insérer dans le $and global.
245
+ // Si le filtre avancé est vide (ex: { $and: [] }), on le retourne quand même pour que le ConditionBuilder puisse s'initialiser correctement.
246
+ return [modelFilter];
247
+ } else {
248
+ // C'est un filtre simple (par colonne).
249
+ // On transforme { champ1: cond1, champ2: cond2 } en [{ champ1: cond1 }, { champ2: cond2 }]
250
+ const c = [];
251
+ filterKeys.forEach(fieldName => {
252
+ if (model.fields.some(f => f.name === fieldName)) {
253
+ const condition = modelFilter[fieldName];
254
+ if (condition && typeof condition === 'object' && Object.keys(condition).length > 0) {
255
+ c.push(condition);
256
+ }
257
+ }
258
+ });
259
+ return c;
260
+ }
222
261
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "data-primals-engine",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
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",
@@ -44,7 +44,8 @@
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": ">=18.0.0",
47
- "react-query": ">=3.0.0"
47
+ "react-query": ">=3.0.0",
48
+ "express": "^5.1.0"
48
49
  },
49
50
  "dependencies": {
50
51
  "@langchain/core": "^0.3.66",
@@ -60,15 +61,13 @@
60
61
  "cookie-parser": "^1.4.7",
61
62
  "cronstrue": "^3.2.0",
62
63
  "csv-parse": "^6.1.0",
63
- "data-primals-engine": "^1.0.11",
64
+ "data-primals-engine": "^1.0.14",
64
65
  "date-fns": "^4.1.0",
65
- "express": "^5.1.0",
66
66
  "express-csrf-double-submit-cookie": "^2.0.0",
67
67
  "express-formidable": "^1.2.0",
68
68
  "express-mongo-sanitize": "^2.2.0",
69
69
  "express-rate-limit": "^8.0.1",
70
70
  "express-session": "^1.18.2",
71
- "i18next": "^25.3.2",
72
71
  "i18next-browser-languagedetector": "^8.2.0",
73
72
  "juice": "^11.0.1",
74
73
  "mathjs": "^14.6.0",
package/server.js CHANGED
@@ -6,6 +6,7 @@
6
6
  import process from "node:process";
7
7
  import {Config, Engine, BenchmarkTool, GameObject, Logger} from "./src/index.js";
8
8
  import sirv from "sirv";
9
+ import express from "express";
9
10
 
10
11
  Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant", "swagger"])
11
12
  Config.Set("middlewares", []);
@@ -14,8 +15,8 @@ const bench = GameObject.Create("Benchmark");
14
15
  const timer = bench.addComponent(BenchmarkTool);
15
16
  timer.start();
16
17
 
17
-
18
- const engine = await Engine.Create();
18
+ const app = express();
19
+ const engine = await Engine.Create({app});
19
20
 
20
21
  if (process.argv.length === 3) {
21
22
  let arg = process.argv[2];
package/src/constants.js CHANGED
@@ -64,6 +64,8 @@ export const emailDefaultConfig = {
64
64
  pass: 'password'
65
65
  }
66
66
 
67
+ export const useAI = true;
68
+
67
69
  /**
68
70
  * Maximum number of models per user
69
71
  * @type {number}
@@ -212,7 +214,19 @@ export const maxTotalPrivateFilesSize = 250 * megabytes;
212
214
  */
213
215
  export const timeoutVM = 5000;
214
216
 
215
- export const defaultMaxRequestData = 50000;
217
+ /**
218
+ * Default maximum number of data per request
219
+ * @type {number}
220
+ */
221
+ export const defaultMaxRequestData = 500;
222
+
223
+ /**
224
+ * Database connections pool size for MongoDB access
225
+ * @type {number}
226
+ */
227
+ export const databasePoolSize = 30;
228
+
229
+
216
230
  /**
217
231
  * Options for the HTML sanitizer
218
232
  * @type {{allowedSchemesByTag: {}, selfClosing: string[], allowedSchemes: string[], enforceHtmlBoundary: boolean, disallowedTagsMode: string, allowProtocolRelative: boolean, allowedAttributes: {a: string[], img: string[], code: string[]}, allowedTags: string[], allowedSchemesAppliedToAttributes: string[]}}
package/src/core.js CHANGED
@@ -11,6 +11,11 @@ export function escapeRegex(string) {
11
11
 
12
12
  export const isDate = dt => String(new Date(dt)) !== 'Invalid Date'
13
13
 
14
+ export const safeAssignObject = (obj, key, value) => {
15
+ if( !["__proto__", "constructor"].includes(key)){
16
+ obj[key] = value;
17
+ }
18
+ }
14
19
  export function debounce(callback, delay=300){
15
20
  var timer;
16
21
  return function(){
@@ -176,9 +181,53 @@ function splitmix32(a) {
176
181
 
177
182
  export const getRand = () =>splitmix32(seed);
178
183
 
179
- export const getRandom = (minInclusive,maxInclusive) => {
180
- return Math.floor(Math.random() * (maxInclusive - minInclusive + 1) + minInclusive);
181
- };
184
+ const MAX_RANGE_SIZE = 2n ** 64n
185
+ const buffer = new BigUint64Array(512)
186
+ let offset = buffer.length
187
+
188
+ /**
189
+ * Returns a cryptographically secure random integer between min and max, inclusive.
190
+ *
191
+ * @param {number} min - the lowest integer in the desired range (inclusive)
192
+ * @param {number} max - the highest integer in the desired range (inclusive)
193
+ * @returns {number} Random number
194
+ */
195
+
196
+ export function getRandom(min, max) {
197
+ if (!(Number.isSafeInteger(min) && Number.isSafeInteger(max))) {
198
+ throw Error("min and max must be safe integers")
199
+ }
200
+ if (min > max) {
201
+ throw Error("min must be less than or equal to max")
202
+ }
203
+ const bmin = BigInt(min)
204
+ const rangeSize = BigInt(max) - bmin + 1n
205
+ const rejectionThreshold = MAX_RANGE_SIZE - (MAX_RANGE_SIZE % rangeSize)
206
+ let result;
207
+ do {
208
+ if (offset >= buffer.length) {
209
+ crypto.getRandomValues(buffer)
210
+ offset = 0
211
+ }
212
+ result = buffer[offset++]
213
+ } while (result >= rejectionThreshold)
214
+ return Number(bmin + result % rangeSize)
215
+ }
216
+
217
+ /**
218
+ * Returns a cryptographically secure random integer between min and max, inclusive.
219
+ *
220
+ * @param {number} minInclusive - the lowest integer in the desired range (inclusive)
221
+ * @param {number} maxInclusive - the highest integer in the desired range (inclusive)
222
+ * @returns {number} Random number
223
+ */
224
+
225
+ export function getBrowserRandom(minInclusive, maxInclusive) {
226
+ const randomBuffer = new Uint32Array(1);
227
+ (window.crypto || window.msCrypto).getRandomValues(randomBuffer);
228
+ const r = ( randomBuffer[0] / (0xffffffff + 1) );
229
+ return Math.floor(r * (maxInclusive - minInclusive + 1) + minInclusive);
230
+ }
182
231
 
183
232
  export function randomDate(start, end) {
184
233
  return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
package/src/engine.js CHANGED
@@ -4,7 +4,7 @@ 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 {cookiesSecret, dbName} from "./constants.js";
7
+ import {cookiesSecret, databasePoolSize, dbName} from "./constants.js";
8
8
  import http from "http";
9
9
  import cookieParser from "cookie-parser";
10
10
  import requestIp from 'request-ip';
@@ -13,20 +13,41 @@ import {defaultModels} from "./defaultModels.js";
13
13
  import {DefaultUserProvider} from "./providers.js";
14
14
  import formidableMiddleware from 'express-formidable';
15
15
  import sirv from "sirv";
16
+ import * as tls from "node:tls";
16
17
 
17
18
  // Constants
18
19
  const isProduction = process.env.NODE_ENV === 'production'
19
20
 
21
+ let caFile, certFile, keyFile;
22
+ try {
23
+ if (process.env.CA_CERT)
24
+ caFile = fs.readFileSync(process.env.CA_CERT || './ca');
25
+ } catch (e) {}
26
+ try {
27
+ if (process.env.CERT)
28
+ certFile = fs.readFileSync(process.env.CERT || '');
29
+ }catch (e) {}
30
+ try{
31
+ if (process.env.CERT_KEY)
32
+ keyFile = fs.readFileSync(process.env.CERT_KEY || './k');
33
+ } catch (e) {}
34
+
35
+ const secureContext = tls.createSecureContext({
36
+ ca: caFile, cert: certFile, key: keyFile
37
+ });
38
+
39
+ const isTlsActive = !(!process.env.TLS || ["0", "false"].includes(process.env.TLS.toLowerCase()));
40
+
20
41
  // Connection URL
21
42
  export const dbUrl = process.env.CI ? 'mongodb://mongodb:27017' : (process.env.MONGO_DB_URL || 'mongodb://127.0.0.1:27017');
22
- export const MongoClient = new InternalMongoClient(dbUrl, { maxPoolSize: 20 });
43
+ export const MongoClient = new InternalMongoClient(dbUrl, { maxPoolSize: databasePoolSize, tls: isTlsActive, secureContext });
23
44
 
24
45
  // Database Name
25
46
  export const MongoDatabase = MongoClient.db(dbName);
26
47
 
27
48
 
28
49
  export const Engine = {
29
- Create: async (options) => {
50
+ Create: async (options = { app : null}) => {
30
51
  const engine = GameObject.Create("Engine");
31
52
  console.log("Creating engine", Config.Get('modules'));
32
53
  engine.addComponent(Logger);
@@ -38,8 +59,11 @@ export const Engine = {
38
59
  engine.getComponent(Logger).info(`Custom UserProvider '${providerInstance.constructor.name}' has been set.`);
39
60
  };
40
61
 
62
+ if (!options.app) {
63
+ options.app = express();
64
+ }
41
65
 
42
- const app = express();
66
+ const { app } = options;
43
67
  // Allows you to set port in the project properties.
44
68
  app.set('port', process.env.PORT || 3000);
45
69
  app.set('engine', engine);
@@ -106,12 +130,8 @@ export const Engine = {
106
130
  engine._modules = e;
107
131
  return Promise.resolve();
108
132
  });
109
- let server;
110
133
 
111
- app.use(sirv('client/dist', {
112
- single: true,
113
- dev: process.env.NODE_ENV === 'development'
114
- }));
134
+ let server;
115
135
 
116
136
  engine.start = async (port, cb) =>{
117
137
  // Use connect method to connect to the server
@@ -132,6 +152,18 @@ export const Engine = {
132
152
  if (cb)
133
153
  await cb();
134
154
 
155
+ engine.get('/api/health', (req, res) => {
156
+ res.status(200).json({
157
+ status: 'ok',
158
+ timestamp: new Date().toISOString()
159
+ });
160
+ });
161
+
162
+ app.use(sirv('client/dist', {
163
+ single: true,
164
+ dev: process.env.NODE_ENV === 'development'
165
+ }));
166
+
135
167
  process.on('uncaughtException', function (exception) {
136
168
  console.error(exception);
137
169
  fs.appendFile('issues.txt', JSON.stringify({ code: exception.code, message: exception.message, stack: exception.stack }), function (err) {
@@ -139,7 +171,7 @@ export const Engine = {
139
171
  throw err;
140
172
  }
141
173
  });
142
- process.exit(0);
174
+ process.exit(1);
143
175
  });
144
176
  }
145
177
 
@@ -171,12 +203,6 @@ export const Engine = {
171
203
  engine.resetModels = async () => {
172
204
  await deleteModels();
173
205
  };
174
- engine.get('/api/health', (req, res) => {
175
- res.status(200).json({
176
- status: 'ok',
177
- timestamp: new Date().toISOString()
178
- });
179
- });
180
206
  return engine;
181
207
  }
182
208
  }
package/src/i18n.js CHANGED
@@ -5,7 +5,13 @@ import LanguageDetector from "i18next-browser-languagedetector";
5
5
  export const translations = {
6
6
  fr: {
7
7
  translation: {
8
+ "datatable.advancedFilter.title": "Filtre avancé (MongoDB)",
9
+ "datatable.advancedFilter.desc": "Créez de toute pièce vos filtres avancés, avec les opérateurs d'aggrégation de MongoDB disponibles ici.",
8
10
 
11
+ "editData": "Éditer dans {{0}}",
12
+ "btns.duplicate": "Dupliquer",
13
+ "btns.edit": "Modifier",
14
+ "btns.delete": "Supprimer",
9
15
  "field_return_status_hint": "Le statut actuel de la demande de retour (ex: Demandé, Approuvé, Remboursé).",
10
16
  "field_workflowRun_completedAt_hint": "Horodatage de la fin de l'exécution (réussie ou échouée).",
11
17
  "field_employee_socialSecurityNumber_hint": "Numéro de sécurité sociale de l'employé.",
@@ -1235,6 +1241,13 @@ export const translations = {
1235
1241
  en: {
1236
1242
  translation: {
1237
1243
 
1244
+ "datatable.advancedFilter.title": "Advanced Filter (MongoDB)",
1245
+ "datatable.advancedFilter.desc": "Create your own advanced filters from scratch, using MongoDB's aggregation operators available here.",
1246
+
1247
+ "editData": "Edit in {{0}}",
1248
+ "btns.duplicate": "Duplicate",
1249
+ "btns.edit": "Edit",
1250
+ "btns.delete": "Delete",
1238
1251
  "field_workflowRun_completedAt_hint": "Timestamp of when the execution ended (successfully or failed).",
1239
1252
  "field_employee_socialSecurityNumber_hint": "Employee's social security number.",
1240
1253
 
@@ -2462,6 +2475,13 @@ export const translations = {
2462
2475
  },
2463
2476
  es: {
2464
2477
  translation: {
2478
+ "datatable.advancedFilter.title": "Filtro avanzado (MongoDB)",
2479
+ "datatable.advancedFilter.desc": "Cree sus propios filtros avanzados desde cero, utilizando los operadores de agregación de MongoDB disponibles aquí.",
2480
+
2481
+ "editData": "Editar en {{0}}",
2482
+ "btns.duplicate": "Duplicar",
2483
+ "btns.edit": "Editar",
2484
+ "btns.delete": "Eliminar",
2465
2485
  "field_return_status_hint": "El estado actual de la solicitud de devolución (ej: Solicitado, Aprobado, Reembolsado).",
2466
2486
  "field_workflowRun_completedAt_hint": "Marca de tiempo del final de la ejecución (exitosa o fallida).",
2467
2487
  "field_employee_socialSecurityNumber_hint": "Número de seguridad social del empleado.",
@@ -3724,6 +3744,13 @@ export const translations = {
3724
3744
  },
3725
3745
  pt: {
3726
3746
  translation: {
3747
+ "datatable.advancedFilter.title": "Filtro Avançado (MongoDB)",
3748
+ "datatable.advancedFilter.desc": "Crie os seus próprios filtros avançados a partir do zero, utilizando os operadores de agregação do MongoDB disponíveis aqui.",
3749
+
3750
+ "editData": "Editar em {{0}}",
3751
+ "btns.duplicate": "Duplicar",
3752
+ "btns.edit": "Editar",
3753
+ "btns.delete": "Apagar",
3727
3754
  "assistant.type": "Digite sua mensagem...",
3728
3755
  "assistant.welcome": "Olá! Como posso ajudá-lo com seus dados?",
3729
3756
  "assistant.named": "Assistente {{named}}",
@@ -3789,6 +3816,12 @@ export const translations = {
3789
3816
  },
3790
3817
  de: {
3791
3818
  translation: {
3819
+ "datatable.advancedFilter.title": "Erweiterter Filter (MongoDB)",
3820
+ "datatable.advancedFilter.desc": "Erstellen Sie Ihre eigenen erweiterten Filter von Grund auf mit den hier verfügbaren Aggregationsoperatoren von MongoDB.",
3821
+ "editData": "Bearbeiten in {{0}}",
3822
+ "btns.duplicate": "Duplizieren",
3823
+ "btns.edit": "Bearbeiten",
3824
+ "btns.delete": "Löschen",
3792
3825
  "field_workflowRun_completedAt_hint": "Zeitstempel des Abschlusses (erfolgreich oder fehlgeschlagen).",
3793
3826
  "field_employee_socialSecurityNumber_hint": "Sozialversicherungsnummer des Mitarbeiters.",
3794
3827
  "field_shipment_order_hint": "Die mit dieser Sendung verknüpfte Bestellung.",
@@ -4931,6 +4964,12 @@ export const translations = {
4931
4964
  },
4932
4965
  it: {
4933
4966
  translation: {
4967
+ "datatable.advancedFilter.title": "Filtro avanzato (MongoDB)",
4968
+ "datatable.advancedFilter.desc": "Crea i tuoi filtri avanzati da zero, utilizzando gli operatori di aggregazione di MongoDB disponibili qui.",
4969
+ "editData": "Modifica in {{0}}",
4970
+ "btns.duplicate": "Duplica",
4971
+ "btns.edit": "Modifica",
4972
+ "btns.delete": "Elimina",
4934
4973
  "field_workflowRun_completedAt_hint": "Timestamp del termine dell'esecuzione (successo o fallimento).",
4935
4974
  "field_employee_socialSecurityNumber_hint": "Numero di previdenza sociale del dipendente.",
4936
4975
  "field_shipment_order_hint": "L'ordine associato a questa spedizione.",
@@ -6126,6 +6165,12 @@ export const translations = {
6126
6165
  },
6127
6166
  cs: {
6128
6167
  translation: {
6168
+ "datatable.advancedFilter.title": "Rozšířený filtr (MongoDB)",
6169
+ "datatable.advancedFilter.desc": "Vytvořte si vlastní pokročilé filtry od nuly pomocí agregačních operátorů MongoDB dostupných zde.",
6170
+ "editData": "Upravit v {{0}}",
6171
+ "btns.duplicate": "Duplikovat",
6172
+ "btns.edit": "Upravit",
6173
+ "btns.delete": "Smazat",
6129
6174
  "field_return_status_hint": "Aktuální stav žádosti o vrácení (např.: Požadováno, Schváleno, Vráceno).",
6130
6175
  "field_workflowRun_completedAt_hint": "Časové razítko dokončení provedení (úspěšného nebo neúspěšného).",
6131
6176
  "field_employee_socialSecurityNumber_hint": "Rodné číslo zaměstnance.",
@@ -6966,6 +7011,12 @@ export const translations = {
6966
7011
  },
6967
7012
  ru: {
6968
7013
  translation: {
7014
+ "datatable.advancedFilter.title": "Расширенный фильтр (MongoDB)",
7015
+ "datatable.advancedFilter.desc": "Создайте свои собственные расширенные фильтры с нуля, используя операторы агрегации MongoDB, доступные здесь",
7016
+ "editData": "Редактировать в {{0}}",
7017
+ "btns.duplicate": "Дублировать",
7018
+ "btns.edit": "Редактировать",
7019
+ "btns.delete": "Удалить",
6969
7020
  "field_workflowRun_completedAt_hint": "Метка времени завершения выполнения (успешного или неудачного).",
6970
7021
  "field_employee_socialSecurityNumber_hint": "Номер социального страхования сотрудника.",
6971
7022
  "field_shipment_order_hint": "Заказ, связанный с этой отгрузкой.",
@@ -8161,7 +8212,12 @@ export const translations = {
8161
8212
  },
8162
8213
  ar: {
8163
8214
  translation: {
8164
-
8215
+ "datatable.advancedFilter.title": "مرشح متقدم (MongoDB)",
8216
+ "datatable.advancedFilter.desc": "أنشئ مرشحاتك المتقدمة من الصفر، باستخدام عوامل تجميع MongoDB المتوفرة هنا",
8217
+ "editData": "تعديل في {{0}}",
8218
+ "btns.duplicate": "تكرار",
8219
+ "btns.edit": "تعديل",
8220
+ "btns.delete": "حذف",
8165
8221
  "field_return_status_hint": "الحالة الحالية لطلب الإرجاع (مثال: مطلوب، معتمد، تم استرداده).",
8166
8222
  "field_workflowRun_completedAt_hint": "طابع زمني لانتهاء التنفيذ (نجاحًا أو فشلًا).",
8167
8223
  "field_employee_socialSecurityNumber_hint": "رقم الضمان الاجتماعي للموظف.",
@@ -9407,7 +9463,12 @@ export const translations = {
9407
9463
  },
9408
9464
  sv: {
9409
9465
  translation: {
9410
-
9466
+ "datatable.advancedFilter.title": "Avancerat filter (MongoDB)",
9467
+ "datatable.advancedFilter.desc": "Skapa dina egna avancerade filter från grunden med hjälp av MongoDBs aggregeringsoperatorer som finns här.",
9468
+ "editData": "Redigera i {{0}}",
9469
+ "btns.duplicate": "Duplicera",
9470
+ "btns.edit": "Redigera",
9471
+ "btns.delete": "Ta bort",
9411
9472
  "field_return_status_hint": "Den aktuella statusen för returförfrågan (t.ex. Begärd, Godkänd, Återbetald).",
9412
9473
  "field_workflowRun_completedAt_hint": "Tidsstämpel för när körningen avslutades (lyckad eller misslyckad).",
9413
9474
  "field_employee_socialSecurityNumber_hint": "Anställds personnummer.",
@@ -10551,6 +10612,12 @@ export const translations = {
10551
10612
  },
10552
10613
  el: {
10553
10614
  translation: {
10615
+ "datatable.advancedFilter.title": "Προηγμένο Φίλτρο (MongoDB)",
10616
+ "datatable.advancedFilter.desc": "Δημιουργήστε τα δικά σας προηγμένα φίλτρα από την αρχή, χρησιμοποιώντας τους τελεστές συνάθροισης της MongoDB που είναι διαθέσιμοι εδώ.",
10617
+ "editData": "Επεξεργασία στο {{0}}",
10618
+ "btns.duplicate": "Διπλότυπο",
10619
+ "btns.edit": "Επεξεργασία",
10620
+ "btns.delete": "Διαγραφή",
10554
10621
  "field_workflowRun_completedAt_hint": "Χρονική σήμανση της ολοκλήρωσης της εκτέλεσης (επιτυχής ή αποτυχημένη).",
10555
10622
  "field_employee_socialSecurityNumber_hint": "Ο αριθμός κοινωνικής ασφάλισης του υπαλλήλου.",
10556
10623
  "field_shipment_order_hint": "Η παραγγελία που σχετίζεται με αυτήν την αποστολή.",
@@ -11680,6 +11747,12 @@ export const translations = {
11680
11747
  },
11681
11748
  fa: {
11682
11749
  translation: {
11750
+ "datatable.advancedFilter.title": "فیلتر پیشرفته (MongoDB)",
11751
+ "datatable.advancedFilter.desc": "با استفاده از عملگرهای تجمیع MongoDB که در اینجا موجود است، فیلترهای پیشرفته خود را از ابتدا ایجاد کنید.",
11752
+ "editData": "ویرایش در {{0}}",
11753
+ "btns.duplicate": "کپی",
11754
+ "btns.edit": "ویرایش",
11755
+ "btns.delete": "حذف",
11683
11756
  "field_return_status_hint": "وضعیت فعلی درخواست مرجوعی (مثال: درخواست شده، تأیید شده، مسترد شده).",
11684
11757
  "field_workflowRun_completedAt_hint": "مهر زمانی پایان اجرا (موفق یا ناموفق).",
11685
11758
  "field_employee_socialSecurityNumber_hint": "شماره تأمین اجتماعی کارمند.",
package/src/migrate.js CHANGED
@@ -3,16 +3,15 @@
3
3
  import process from "node:process";
4
4
  import fs from "node:fs/promises";
5
5
  import path from "node:path";
6
- // FIX: Import 'pathToFileURL' instead of 'fileURLToPath'
7
6
  import { pathToFileURL } from 'node:url';
8
7
  import { Engine, MongoDatabase } from "./engine.js";
9
8
  import { Logger } from "./gameObject.js";
10
9
  import { Config } from "./config.js";
11
- import chalk from "chalk"; // Pour une sortie plus lisible. Assurez-vous que 'chalk' est dans vos dépendances.
10
+ import chalk from "chalk";
12
11
 
13
12
  // Configuration de base
14
13
  Config.Set("modules", ["mongodb"]);
15
- const MIGRATIONS_DIR = path.resolve(process.cwd(), 'server', 'src', 'migrations');
14
+ const MIGRATIONS_DIR = path.resolve(process.cwd(), 'migrations');
16
15
  const MIGRATIONS_COLLECTION = 'migrations_log';
17
16
 
18
17
  const engine = await Engine.Create();
@@ -1635,9 +1635,9 @@ export async function onInit(defaultEngine) {
1635
1635
  engine.put('/api/model/:id', [middlewareAuthenticator, userInitiator, setTimeoutMiddleware(15000)], async (req, res) => {
1636
1636
  const result = await editModel(req.me, req.params.id, req.fields);
1637
1637
  if( result.success){
1638
- return res.status(result.statusCode || '200').json(result);
1638
+ return res.status(result.statusCode || 200).json(result);
1639
1639
  }else{
1640
- return res.status(result.statusCode || '500').json(result);
1640
+ return res.status(result.statusCode || 500).json(result);
1641
1641
  }
1642
1642
  });
1643
1643
 
@@ -4038,9 +4038,18 @@ export const searchData = async ({user, query}) => {
4038
4038
  {$eq: ["$_model", fi.relation]},
4039
4039
  {$eq: ["$_user", user.username]},
4040
4040
  fi.multiple ? {
4041
- $in: [{$toString: "$_id"}, {$ifNull: ['$$convertedId', []]}]
4041
+ $in: [{ $toString: "$_id" }, {
4042
+ $map: {
4043
+ input: { $ifNull: ["$$convertedId", []] }, // On utilise le tableau d'IDs, ou un tableau vide s'il est null
4044
+ as: "relationId",
4045
+ in: { $toString: "$$relationId" }
4046
+ }
4047
+ }]
4042
4048
  } : {
4043
- $eq: [{$toString: "$_id"}, '$$convertedId']
4049
+ $eq: [
4050
+ { $toString: "$_id" },
4051
+ { $convert: { input: '$$convertedId', to: "string", onError: '' } }
4052
+ ]
4044
4053
  }
4045
4054
  ]
4046
4055
  ]
@@ -4315,6 +4324,7 @@ export const searchData = async ({user, query}) => {
4315
4324
  } else if (fi.type === 'array') {
4316
4325
  // Handle array filtering here
4317
4326
  if (data[fi.name]) {
4327
+ console.log('array filtering', data[fi.name]);
4318
4328
  pipelines.push({
4319
4329
  $match: {
4320
4330
  $expr: {
@@ -4350,6 +4360,7 @@ export const searchData = async ({user, query}) => {
4350
4360
 
4351
4361
  let pipelines = [];
4352
4362
  if( allIds.length ){
4363
+ console.log({allIds});
4353
4364
  const id = {$in: ["$_id", allIds.map(m => new ObjectId(m))]};
4354
4365
  pipelines.push({
4355
4366
  $match: { $expr: id }
@@ -13,15 +13,6 @@ export async function onInit(defaultEngine) {
13
13
 
14
14
  const isProduction = process.env.NODE_ENV === 'production'
15
15
 
16
- let ca, cert, key;
17
- try {
18
- ca = fs.readFileSync('certs/mongodb-cert.crt');
19
- cert = fs.readFileSync('certs/mongodb.pem');
20
- key = fs.readFileSync(`certs/mongodb-cert.key`);
21
- } catch (e) {
22
-
23
- }
24
-
25
16
  modelsCollection = MongoDatabase.collection("models");
26
17
  datasCollection = MongoDatabase.collection("datas");
27
18
  filesCollection = MongoDatabase.collection("files");
package/src/packs.js CHANGED
@@ -390,8 +390,9 @@ export const getAllPacks = async () => {
390
390
  return {
391
391
  name: m.name,
392
392
  permissions: {
393
- "$find": {
394
- "$in": ["$name", m.perms]
393
+ "$link": {
394
+ "$in": ["$name", m.perms],
395
+ "_model": "permission"
395
396
  }
396
397
  }
397
398
  }
@@ -407,7 +408,7 @@ export const getAllPacks = async () => {
407
408
  "code": "fr"
408
409
  }],
409
410
  "translation": [
410
- { "lang": { "$find": { "$eq": ["$code", "fr"]}}, "key": "Visitor alerts", "value": "Alertes visiteurs" }
411
+ { "lang": { "$link": { "$eq": ["$code", "fr"]}, "_model": "lang"}, "key": "Visitor alerts", "value": "Alertes visiteurs" }
411
412
  ]
412
413
  }
413
414
  }
@@ -1,20 +0,0 @@
1
- /**
2
- * Migration: setting content field to 'fr' in 'content' model
3
- * Created at: 2024-05-21T10:00:00.000Z
4
- */
5
-
6
- export const up = async (db) => {
7
- const datasCollection = db.collection("datas");
8
- const content = await datasCollection.find({ _model:"content"}).toArray();
9
- await Promise.all(content.map(async (doc) => {
10
- if (typeof(doc.html)==='string') {
11
- const c = { "fr" : doc.html };
12
- await datasCollection.updateOne({_id: doc._id}, {$set: {html: c}});
13
- }
14
- }));
15
- console.log("Migration UP: setting content field to 'fr' in 'content' model");
16
- };
17
-
18
- export const down = async (db) => {
19
- console.log("Migration DOWN: noting to do");
20
- };