data-primals-engine 1.1.8 → 1.2.0

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.
@@ -10,7 +10,7 @@ import process from "node:process";
10
10
  import {randomColor} from "randomcolor";
11
11
  import cronstrue from 'cronstrue/i18n.js';
12
12
  import { setTimeoutMiddleware } from '../middlewares/timeout.js';
13
-
13
+ import { mkdir } from 'node:fs/promises';
14
14
  import {
15
15
  anonymizeText,
16
16
  encryptValue,
@@ -981,13 +981,10 @@ async function runStatefulAlertJob(alertId) {
981
981
  // 3. Evaluate the trigger condition
982
982
  const apiFilter = (alertDoc.triggerCondition);
983
983
  const { count } = await searchData({
984
- user: { username: alertDoc._user },
985
- query: {
986
- model: alertDoc.targetModel,
987
- filter: apiFilter,
988
- limit: 1
989
- }
990
- });
984
+ model: alertDoc.targetModel,
985
+ filter: apiFilter,
986
+ limit: 1
987
+ }, { username: alertDoc._user });
991
988
 
992
989
  // 4. If condition is met, send notification and update state
993
990
  if (count > 0) {
@@ -1233,17 +1230,14 @@ export async function handleCustomEndpointRequest(req, res) {
1233
1230
  try {
1234
1231
  // 1. Trouver l'endpoint correspondant dans la base de données
1235
1232
  const endpointSearch = await searchData({
1236
- user,
1237
- query: {
1238
- model: 'endpoint',
1239
- filter: {
1240
- path: path,
1241
- method: method,
1242
- isActive: true
1243
- },
1244
- limit: 1
1245
- }
1246
- });
1233
+ model: 'endpoint',
1234
+ filter: {
1235
+ path: path,
1236
+ method: method,
1237
+ isActive: true
1238
+ },
1239
+ limit: 1
1240
+ }, user);
1247
1241
 
1248
1242
  if (endpointSearch.count === 0) {
1249
1243
  logger.warn(`[Endpoint] 404 - No active endpoint found for user '${user.username}', path '${path}', method '${method}'.`);
@@ -1382,6 +1376,9 @@ export async function onInit(defaultEngine) {
1382
1376
  }
1383
1377
 
1384
1378
 
1379
+ // Create the uploads directories
1380
+ await mkdir(path.join("uploads", "tmp"),{ recursive: true});
1381
+
1385
1382
  }else {
1386
1383
  modelsCollection = getCollection("models");
1387
1384
  datasCollection = getCollection("datas");
@@ -1396,7 +1393,7 @@ export async function onInit(defaultEngine) {
1396
1393
  schedule.scheduleJob("0 0 * * *", async () => {
1397
1394
  const dt = new Date();
1398
1395
  dt.setTime(dt.getTime()-1000*3600*24*14);
1399
- await deleteData("request", [], {"$lt": ["$timestamp",dt.toISOString()]}, null, false);
1396
+ await deleteData("request", {"$lt": ["$timestamp",dt.toISOString()]}, null, false);
1400
1397
  });
1401
1398
  await scheduleWorkflowTriggers();
1402
1399
 
@@ -1527,14 +1524,11 @@ export async function onInit(defaultEngine) {
1527
1524
 
1528
1525
  // On utilise la fonction de recherche interne de l'application
1529
1526
  const searchResult = await searchData({
1530
- query: {
1531
- model,
1532
- filter: processedFilter,
1533
- limit, // Optimisation : pas besoin de plus de résultats
1534
- page: 1
1535
- },
1536
- user: user
1537
- });
1527
+ model,
1528
+ filter: processedFilter,
1529
+ limit, // Optimisation : pas besoin de plus de résultats
1530
+ page: 1
1531
+ }, user);
1538
1532
 
1539
1533
  // searchData devrait renvoyer un `count` total des documents correspondants
1540
1534
  const isCompleted = searchResult.count >= limit;
@@ -1710,6 +1704,48 @@ export async function onInit(defaultEngine) {
1710
1704
  });
1711
1705
 
1712
1706
 
1707
+ engine.post('/api/model/search', [middlewareAuthenticator, userInitiator], async (req, res) => {
1708
+ const { query } = req.fields;
1709
+ const user = req.me;
1710
+
1711
+ if (!query || typeof query !== 'string') {
1712
+ return res.status(400).json({ success: false, error: 'A search query string is required.' });
1713
+ }
1714
+
1715
+ try {
1716
+ // Utilise une expression régulière pour une recherche insensible à la casse
1717
+ const searchRegex = new RegExp(query, 'i');
1718
+
1719
+ const results = await modelsCollection.find({
1720
+ // Cherche dans les modèles de l'utilisateur OU les modèles partagés
1721
+ $or: [
1722
+ { _user: user.username },
1723
+ { _user: { $exists: false } }
1724
+ ],
1725
+ // Cherche dans le nom OU la description
1726
+ $and: [
1727
+ { $or: [
1728
+ { name: { $regex: searchRegex } },
1729
+ { description: { $regex: searchRegex } }
1730
+ ]}
1731
+ ]
1732
+ }, {
1733
+ // On ne retourne que les informations utiles pour l'IA, pas tout le modèle
1734
+ projection: {
1735
+ name: 1,
1736
+ description: 1,
1737
+ _id: 0
1738
+ }
1739
+ }).limit(10).toArray(); // Limite à 10 résultats pour ne pas surcharger
1740
+
1741
+ res.json({ success: true, models: results });
1742
+
1743
+ } catch (error) {
1744
+ logger.error(`[Model Search] Error searching models for query "${query}":`, error);
1745
+ res.status(500).json({ success: false, error: 'An internal server error occurred.' });
1746
+ }
1747
+ });
1748
+
1713
1749
  engine.post('/api/model/generate', [middlewareAuthenticator, userInitiator, assistantGlobalLimiter, generateLimiter, setTimeoutMiddleware(30000)], async (req, res) => {
1714
1750
  // --- NOUVELLE LOGIQUE : Accepter le prompt ET un modèle existant ---
1715
1751
  const { prompt, history = [], existingModel } = req.fields;
@@ -1820,7 +1856,7 @@ export async function onInit(defaultEngine) {
1820
1856
  const { pack } = req.fields;
1821
1857
 
1822
1858
  try {
1823
- const {data, count} = await searchData({query: {...req.query, model: req.fields.model || req.query.model, filter: req.fields.filter, pack}, user: req.me });
1859
+ const {data, count} = await searchData({...req.query, model: req.fields.model || req.query.model, filter: req.fields.filter, pack}, req.me);
1824
1860
 
1825
1861
  if( req.query.attachment ) {
1826
1862
  res.attachment(req.query.attachment);
@@ -1845,7 +1881,7 @@ export async function onInit(defaultEngine) {
1845
1881
 
1846
1882
  engine.delete('/api/data/:ids', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger, setTimeoutMiddleware(15000)], async (req, res) => {
1847
1883
  const ids = req.params.ids.split(',');
1848
- const r = await deleteData(req.fields.model, ids, {}, req.me);
1884
+ const r = await deleteData(req.fields.model, ids, req.me);
1849
1885
  if( r.error) {
1850
1886
  return res.status(r.statusCode || 400).json(r);
1851
1887
  }else{
@@ -1854,7 +1890,7 @@ export async function onInit(defaultEngine) {
1854
1890
  });
1855
1891
 
1856
1892
  engine.delete('/api/data', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger, setTimeoutMiddleware(15000)], async (req, res) => {
1857
- const r = await deleteData(req.fields.model, [], req.fields.filter, req.me);
1893
+ const r = await deleteData(req.fields.model, req.fields.filter, req.me);
1858
1894
  if( r.error) {
1859
1895
  return res.status(r.statusCode || 400).json(r);
1860
1896
  }else{
@@ -2344,12 +2380,6 @@ export async function onInit(defaultEngine) {
2344
2380
  * }
2345
2381
  * Returns: Array of aggregated data points (e.g., [{ label: '...', value: ... }]) or an error.
2346
2382
  */
2347
- // Dans server/src/modules/data.js, modifiez la route POST /api/charts/aggregate
2348
-
2349
- // Dans server/src/modules/data.js, modifiez la route POST /api/charts/aggregate
2350
- // C:/Dev/hackersonline-engine/server/src/modules/data.js
2351
-
2352
- // ... (autres imports et code)
2353
2383
 
2354
2384
  engine.post('/api/charts/aggregate', [throttle, middlewareAuthenticator, userInitiator, ...userMiddlewares, setTimeoutMiddleware(15000)], async (req, res) => {
2355
2385
  // --- Récupérer groupByLabelField ---
@@ -3236,13 +3266,10 @@ async function processRelations(docToProcess, model, collection, me, idMap) {
3236
3266
  batchFinds.push({
3237
3267
  field: field.name,
3238
3268
  promise: searchData({
3239
- user: me,
3240
- query: {
3241
- filter: value.$find,
3242
- limit: field.multiple ? 0 : 1,
3243
- model: field.relation
3244
- }
3245
- }),
3269
+ filter: value.$find,
3270
+ limit: field.multiple ? 0 : 1,
3271
+ model: field.relation
3272
+ }, me),
3246
3273
  multiple: field.multiple
3247
3274
  });
3248
3275
  }
@@ -3655,7 +3682,7 @@ const internalEditOrPatchData = async (modelName, filter, data, files, user, isP
3655
3682
  }
3656
3683
 
3657
3684
  // 2. Récupération des documents existants et de leur hash original
3658
- const existingDocs = (await searchData({user, query: {model: modelName, filter}}))?.data;
3685
+ const existingDocs = (await searchData({model: modelName, filter}, user))?.data;
3659
3686
  if (!existingDocs || existingDocs.length === 0) {
3660
3687
  return {success: false, error: i18n.t("api.data.notFound")};
3661
3688
  }
@@ -3856,7 +3883,8 @@ async function handleScheduledJobs(modelName, existingDocs, collection, updateDa
3856
3883
  }
3857
3884
  }
3858
3885
 
3859
- export const deleteData = async (modelName, ids = [], filter, user ={}, triggerWorkflow, waitForWorkflow = false) => {
3886
+
3887
+ export const deleteData = async (modelName, filter, user ={}, triggerWorkflow, waitForWorkflow = false) => {
3860
3888
 
3861
3889
  try {
3862
3890
  const collection = await getCollectionForUser(user);
@@ -3871,8 +3899,8 @@ export const deleteData = async (modelName, ids = [], filter, user ={}, triggerW
3871
3899
  });
3872
3900
 
3873
3901
  // Ajouter le filtre par IDs si fourni
3874
- if (ids && ids.length > 0) {
3875
- findFilter.push({"$in": ["$_id", ids.map(m => new ObjectId(m))]});
3902
+ if (Array.isArray(filter) && filter.length > 0) {
3903
+ findFilter.push({"$in": ["$_id", filter.map(m => new ObjectId(m))]});
3876
3904
  }
3877
3905
 
3878
3906
  // Ajouter le filtre par nom de modèle si fourni (utile si 'filter' est utilisé seul)
@@ -4071,7 +4099,7 @@ export const deleteData = async (modelName, ids = [], filter, user ={}, triggerW
4071
4099
 
4072
4100
  // ... (le reste du fichier data.js)
4073
4101
 
4074
- export const searchData = async ({user, query}) => {
4102
+ export const searchData = async (query, user) => {
4075
4103
  const { page, limit, sort, model, ids, timeout, pack } = query; // Les filtres de la requête (attention aux injections MongoDB !)
4076
4104
 
4077
4105
  if( user.username !== 'demo' && isLocalUser(user) && (
@@ -4610,8 +4638,10 @@ export const importData = async(options, files, user) => {
4610
4638
  // let allProcessedData = [];
4611
4639
  // let modelNameForImport = '';
4612
4640
  // --- FIN DE LA MODIFICATION ---
4613
-
4614
- if (file.mimetype === 'application/json' || file.originalFilename.endsWith('.json')) {
4641
+ if( !file.name ){
4642
+ throw new Error("No file provided.");
4643
+ }
4644
+ if (file.type === 'application/json' || file.name.endsWith('.json')) {
4615
4645
  fileProcessed = true;
4616
4646
  const jsonData = await runImportExportWorker('parse-json', { fileContent: fileContent.toString() });
4617
4647
 
@@ -4752,7 +4782,7 @@ export const importData = async(options, files, user) => {
4752
4782
  }
4753
4783
  // --- FIN DE LA MODIFICATION PRINCIPALE ---
4754
4784
 
4755
- } else if (file.mimetype === 'text/csv' || file.originalFilename.endsWith('.csv')) {
4785
+ } else if (file.type === 'text/csv' || file.name.endsWith('.csv')) {
4756
4786
  // --- Logique CSV (inchangée, mais maintenant elle est séparée de la logique JSON) ---
4757
4787
  fileProcessed = true;
4758
4788
  const modelNameForImport = options.model;
@@ -4959,16 +4989,13 @@ export const exportData= async (options, user) =>{
4959
4989
 
4960
4990
  // --- Fetch Data using searchData ---
4961
4991
  const searchParams = {
4962
- user: user,
4963
- query: {
4964
- model: modelName,
4965
- filter: modelSpecificFilter,
4966
- depth: parsedDepth,
4967
- limit: remainingLimit
4968
- }
4992
+ model: modelName,
4993
+ filter: modelSpecificFilter,
4994
+ depth: parsedDepth,
4995
+ limit: remainingLimit
4969
4996
  };
4970
4997
 
4971
- const { data: resultData, count } = await searchData(searchParams);
4998
+ const { data: resultData, count } = await searchData(searchParams, user);
4972
4999
 
4973
5000
  if (resultData && resultData.length > 0) {
4974
5001
  exportResults[modelName] = resultData;
@@ -5073,7 +5100,6 @@ function isValidAggregationOperator(operator) {
5073
5100
 
5074
5101
  return [...arithmeticOperators, ...comparisonOperators, ...stringOperators, ...conditionalOperators].includes(operator);
5075
5102
  }
5076
- // C:/Dev/hackersonline-engine/server/src/modules/data.js
5077
5103
 
5078
5104
  /**
5079
5105
  * Gère les traductions spécifiques à l'utilisateur et traite les données de manière récursive
@@ -5357,8 +5383,6 @@ const readKeyFromFile = (user) => {
5357
5383
  return null;
5358
5384
  };
5359
5385
 
5360
- // C:/Dev/data-primals-engine/src/modules/data.js
5361
-
5362
5386
  export const dumpUserData = async (user) => {
5363
5387
  const s3Config = user.configS3;
5364
5388
  const backupDir = getBackupDir();
@@ -5777,7 +5801,7 @@ export async function installPack(packId, user, lang) {
5777
5801
  const finalSelector = { ...linkSelector };
5778
5802
  delete finalSelector['_model']; // nécessaire
5779
5803
  // CORRECTION 4: Appel corrigé à searchData
5780
- const { data: targetDocs } = await searchData({ user, query: { model: targetModelName, filter: finalSelector } });
5804
+ const { data: targetDocs } = await searchData({model: targetModelName, filter: finalSelector }, user);
5781
5805
 
5782
5806
  if (targetDocs && targetDocs.length > 0) {
5783
5807
  targetIds = targetDocs.map(d => d._id); // Récupère un tableau d'ObjectIds
@@ -5832,11 +5856,6 @@ export const installAllPacks = async () => {
5832
5856
  await packsCollection.insertMany(packs);
5833
5857
  }
5834
5858
 
5835
- // Dans C:/Dev/data-primals-engine/src/modules/data.js
5836
- // Dans C:/Dev/data-primals-engine/src/modules/data.js
5837
-
5838
- // ... (imports inchangés)
5839
-
5840
5859
  export async function handleDemoInitialization(req, res) {
5841
5860
  const user = req.me;
5842
5861
  const body = req.fields;
@@ -197,15 +197,15 @@ export async function executeSafeJavascript(actionDef, context, user) {
197
197
  await jail.set('db', createJailFunction({
198
198
  create: (modelName, dataObject) => insertData(modelName, dataObject, {}, user),
199
199
  find: async (modelName, filter) => {
200
- const result = await searchData({ user, query: { model: modelName, filter } });
200
+ const result = await searchData({ model: modelName, filter }, user);
201
201
  return new ivm.ExternalCopy(result.data).copyInto();
202
202
  },
203
203
  findOne: async (modelName, filter) => {
204
- const result = await searchData({ user, query: { model: modelName, filter, limit: 1 } });
204
+ const result = await searchData({ model: modelName, filter, limit: 1 }, user);
205
205
  return new ivm.ExternalCopy(result.data?.[0] || null).copyInto();
206
206
  },
207
207
  update: (modelName, filter, updateObject) => patchData(modelName, filter, updateObject, {}, user),
208
- delete: (modelName, filter) => deleteData(modelName, null, filter, user)
208
+ delete: (modelName, filter) => deleteData(modelName, filter, user)
209
209
  }));
210
210
 
211
211
  const createLoggerFunction = (level) => {
@@ -228,11 +228,11 @@ export async function executeSafeJavascript(actionDef, context, user) {
228
228
  await jail.set('env', createJailFunction({
229
229
  get: async (variableName) => {
230
230
  if (!variableName) return null;
231
- const result = await searchData({ user, query: { model: 'env', filter: { name: variableName }, limit: 1 } });
231
+ const result = await searchData({ model: 'env', filter: { name: variableName }, limit: 1 }, user);
232
232
  return new ivm.ExternalCopy(result.data?.[0]?.value || null).copyInto();
233
233
  },
234
234
  getAll: async () => {
235
- const result = await searchData({ user, query: { model: 'env' } });
235
+ const result = await searchData({ model: 'env' }, user);
236
236
  const envObject = result.data.reduce((acc, v) => {
237
237
  acc[v.name] = v.value;
238
238
  return acc;
@@ -708,7 +708,7 @@ async function handleDeleteDataAction(actionDef, contextData, user, dbCollection
708
708
  // 5. Call the centralized deleteData function (à créer dans data.js)
709
709
  // Cette fonction devra gérer la recherche préalable pour les workflows 'DataDeleted' et la suppression des fichiers.
710
710
  const deleteResult = await deleteData(
711
- targetModel, [],
711
+ targetModel,
712
712
  selectorObject,
713
713
  user
714
714
  );
@@ -1115,7 +1115,7 @@ export async function triggerWorkflows(triggerData, user, eventType) {
1115
1115
 
1116
1116
  // Exécuter la vérification dans la base de données
1117
1117
  // Utilisation de countDocuments pour une vérification rapide
1118
- const matchCount = await searchData({ user, query: { model: targetModelName, filter: finalFilter, limit: 1 } });
1118
+ const matchCount = await searchData({ model: targetModelName, filter: finalFilter, limit: 1 }, user);
1119
1119
 
1120
1120
  if (!matchCount.count) {
1121
1121
  console.debug(`[Workflow Trigger] Trigger ${trigger._id}: dataFilter non satisfait par la donnée ${dataId}. WorkflowRun non créé.`);
@@ -1198,7 +1198,6 @@ export async function triggerWorkflows(triggerData, user, eventType) {
1198
1198
  * @param {object} user - The user context for database access.
1199
1199
  * @returns {Promise<void>}
1200
1200
  */
1201
- // C:/Dev/hackersonline-engine/server/src/modules/workflow.js
1202
1201
 
1203
1202
  export async function processWorkflowRun(workflowRunId, user) {
1204
1203
  const dbCollection = await getCollectionForUser(user);
@@ -1280,7 +1279,7 @@ export async function processWorkflowRun(workflowRunId, user) {
1280
1279
  try {
1281
1280
  // --- 7. Évaluation des conditions de l'étape ---
1282
1281
  if (currentStepDef.conditions && Object.keys(currentStepDef.conditions).length > 0) {
1283
- const searchResult = await searchData({ user, query: { model: contextData.triggerDataModel, filter: currentStepDef.conditions, limit: 1 } });
1282
+ const searchResult = await searchData({ model: contextData.triggerDataModel, filter: currentStepDef.conditions, limit: 1}, user);
1284
1283
  conditionsMet = searchResult && searchResult.count > 0;
1285
1284
  logger.info(`[processWorkflowRun] Run ID: ${runId}, Step ID: ${currentStepId}: Conditions evaluated. Found ${searchResult ? searchResult.count : 0} match(es). Result: ${conditionsMet}`);
1286
1285
  }
@@ -1478,9 +1477,8 @@ async function handleSendEmailAction(action, triggerData, user) {
1478
1477
 
1479
1478
  // 1. Récupérer la configuration SMTP depuis le modèle 'env' de l'utilisateur
1480
1479
  const envVars = await searchData({
1481
- user,
1482
- query: { model: 'env', limit: 100 } // Limite raisonnable pour les variables d'env
1483
- });
1480
+ model: 'env', limit: 100 } // Limite raisonnable pour les variables d'env
1481
+ , user);
1484
1482
 
1485
1483
  if (!envVars.data || envVars.data.length === 0) {
1486
1484
  throw new Error("Aucune variable d'environnement (modèle 'env') trouvée pour la configuration SMTP.");
package/src/providers.js CHANGED
@@ -91,7 +91,7 @@ export class UserProvider {
91
91
  }
92
92
 
93
93
  async hasFeature(user, feature) {
94
- return this.plans[user.userPlan]?.features.some(f => f === feature);
94
+ return this.plans[user?.userPlan]?.features.some(f => f === feature);
95
95
  }
96
96
 
97
97
  // Ajoutez ici d'autres méthodes nécessaires : findUserById, createUser, etc.
@@ -1,4 +1,3 @@
1
- // C:/Dev/hackersonline-engine/server/src/workers/crypto-worker.js
2
1
  import { parentPort } from 'worker_threads';
3
2
  import crypto from 'node:crypto';
4
3
  import fs from 'node:fs/promises';
@@ -471,7 +471,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
471
471
  const insertResult = await insertData(simpleModel.name, dataToDelete, {}, currentTestUser, false);
472
472
  const docId = insertResult.insertedIds[0];
473
473
 
474
- const deleteResult = await deleteData(simpleModel.name, [docId], {}, currentTestUser, false);
474
+ const deleteResult = await deleteData(simpleModel.name, [docId], currentTestUser);
475
475
 
476
476
  expect(deleteResult.success).toBe(true);
477
477
  expect(deleteResult.deletedCount).toBe(1);
@@ -493,7 +493,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
493
493
  input: '$name',
494
494
  regex: "^Item Filtrable"
495
495
  } };
496
- const deleteResult = await deleteData(simpleModel.name, [], filter, currentTestUser, false);
496
+ const deleteResult = await deleteData(simpleModel.name, filter, currentTestUser);
497
497
 
498
498
  expect(deleteResult.success).toBe(true);
499
499
  expect(deleteResult.deletedCount).toBe(2);
@@ -551,19 +551,16 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
551
551
  it('devrait trouver un document par une condition sur une relation simple ($find)', async () => {
552
552
  const { currentTestUser, comprehensiveTestModelDefinition, relatedModelDefinition } = await initTest();
553
553
  const searchParams = {
554
- user: currentTestUser,
555
- query: {
556
- model: comprehensiveTestModelDefinition.name,
557
- filter: {
558
- relationSingle: {
559
- "$find": { "$and": [{"$eq": ["$$this.relatedValue", 101]}] }
560
- }
561
- },
562
- autoExpand: true,
563
- depth: 8
564
- }
554
+ model: comprehensiveTestModelDefinition.name,
555
+ filter: {
556
+ relationSingle: {
557
+ "$find": { "$and": [{"$eq": ["$$this.relatedValue", 101]}] }
558
+ }
559
+ },
560
+ autoExpand: true,
561
+ depth: 8
565
562
  };
566
- const { data, count } = await searchData(searchParams);
563
+ const { data, count } = await searchData(searchParams, currentTestUser);
567
564
  expect(count).toBe(1);
568
565
  expect(data).toHaveLength(1);
569
566
  expect(data[0]._id.toString()).toBe(docId1.toString());
@@ -575,18 +572,15 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
575
572
  it('ne devrait pas trouver de document si la condition $find sur relation simple ne correspond pas', async () => {
576
573
  const { currentTestUser, comprehensiveTestModelDefinition, relatedModelDefinition } = await initTest();
577
574
  const searchParams = {
578
- user: currentTestUser,
579
- query: {
580
- model: comprehensiveTestModelDefinition.name,
581
- filter: {
582
- relationSingle: {
583
- "$find": { "$eq": ["$$this.relatedName", "NonExistentRelName"] }
584
- }
585
- },
586
- depth: 1
587
- }
575
+ model: comprehensiveTestModelDefinition.name,
576
+ filter: {
577
+ relationSingle: {
578
+ "$find": { "$eq": ["$$this.relatedName", "NonExistentRelName"] }
579
+ }
580
+ },
581
+ depth: 1
588
582
  };
589
- const { data, count } = await searchData(searchParams);
583
+ const { data, count } = await searchData(searchParams, currentTestUser);
590
584
  expect(count).toBe(0);
591
585
  expect(data).toHaveLength(0);
592
586
  });
@@ -594,20 +588,17 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
594
588
  it('devrait trouver des documents par une condition sur une relation multiple ($find)', async () => {
595
589
  const { currentTestUser, comprehensiveTestModelDefinition, relatedModelDefinition } = await initTest();
596
590
  const searchParams = {
597
- user: currentTestUser,
598
- query: {
599
- model: comprehensiveTestModelDefinition.name,
600
- filter: {
601
- $and: [{$ne:["$stringRequired", null]}, {
602
- relationMultiple: { // Le champ qui est un tableau de relations
603
- "$find": {"$eq": ["$$this.relatedValue", 102]} // Condition sur les documents liés
604
- }
605
- }]
606
- },
607
- depth: 1
608
- }
591
+ model: comprehensiveTestModelDefinition.name,
592
+ filter: {
593
+ $and: [{$ne:["$stringRequired", null]}, {
594
+ relationMultiple: { // Le champ qui est un tableau de relations
595
+ "$find": {"$eq": ["$$this.relatedValue", 102]} // Condition sur les documents liés
596
+ }
597
+ }]
598
+ },
599
+ depth: 1
609
600
  };
610
- const { data, count } = await searchData(searchParams);
601
+ const { data, count } = await searchData(searchParams, currentTestUser);
611
602
  expect(count).toBe(1);
612
603
  expect(data).toHaveLength(1);
613
604
  expect(data[0]._id.toString()).toBe(docId1.toString());
@@ -620,19 +611,16 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
620
611
  it('devrait trouver des documents en combinant un filtre normal et un filtre $find', async () => {
621
612
  const { currentTestUser, comprehensiveTestModelDefinition, relatedModelDefinition } = await initTest();
622
613
  const searchParams = {
623
- user: currentTestUser,
624
- query: {
625
- model: comprehensiveTestModelDefinition.name,
626
- filter: {
627
- stringRequired: "SearchDoc1", // Filtre sur le modèle principal
628
- relationSingle: {
629
- "$find": {"$gt": ["$$this.relatedValue", 100] } // Filtre sur la relation
630
- }
631
- },
632
- depth: 1
633
- }
614
+ model: comprehensiveTestModelDefinition.name,
615
+ filter: {
616
+ stringRequired: "SearchDoc1", // Filtre sur le modèle principal
617
+ relationSingle: {
618
+ "$find": {"$gt": ["$$this.relatedValue", 100] } // Filtre sur la relation
619
+ }
620
+ },
621
+ depth: 1
634
622
  };
635
- const { data, count } = await searchData(searchParams);
623
+ const { data, count } = await searchData(searchParams,currentTestUser);
636
624
  expect(count).toBe(1);
637
625
  expect(data).toHaveLength(1);
638
626
  expect(data[0]._id.toString()).toBe(docId1.toString());
@@ -641,26 +629,21 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
641
629
  it('devrait retourner un tableau vide si $find ne correspond à aucun document lié', async () => {
642
630
  const { currentTestUser, comprehensiveTestModelDefinition, relatedModelDefinition } = await initTest();
643
631
  const searchParams = {
644
- user: currentTestUser,
645
- query: {
646
- model: comprehensiveTestModelDefinition.name,
647
- filter: {
648
- relationMultiple: {
649
- "$find": { "$eq": ["$$this.relatedName", "NonExistentRelNameForMultiple"] }
650
- }
651
- },
652
- depth: 1
653
- }
632
+ model: comprehensiveTestModelDefinition.name,
633
+ filter: {
634
+ relationMultiple: {
635
+ "$find": { "$eq": ["$$this.relatedName", "NonExistentRelNameForMultiple"] }
636
+ }
637
+ },
638
+ depth: 1
654
639
  };
655
- const { data, count } = await searchData(searchParams);
640
+ const { data, count } = await searchData(searchParams,currentTestUser);
656
641
  expect(count).toBe(0);
657
642
  expect(data).toHaveLength(0);
658
643
  });
659
644
 
660
645
  });
661
646
 
662
- // Dans C:/Dev/hackersonline-engine/test/data.integration.test.js
663
-
664
647
  describe('installPack', () => {
665
648
  let testPacksColInstance;
666
649
 
@@ -824,8 +807,8 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
824
807
  // Cleanup before starting to ensure a clean state
825
808
  await deleteModels({ name: productModel.name, _user: user.username });
826
809
  await deleteModels({ name: orderModel.name, _user: user.username });
827
- await deleteData(productModel.name, [], {}, user);
828
- await deleteData(orderModel.name, [], {}, user);
810
+ await deleteData(productModel.name, {}, user);
811
+ await deleteData(orderModel.name, {}, user);
829
812
 
830
813
  // Create models
831
814
  await createModel({ ...productModel, _user: user.username });
@@ -843,8 +826,8 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
843
826
  afterAll(async () => {
844
827
  await deleteModels({ name: productModel.name, _user: user.username });
845
828
  await deleteModels({ name: orderModel.name, _user: user.username });
846
- await deleteData(productModel.name, [], {}, user);
847
- await deleteData(orderModel.name, [], {}, user);
829
+ await deleteData(productModel.name, {}, user);
830
+ await deleteData(orderModel.name, {}, user);
848
831
  });
849
832
 
850
833
  it('should ALLOW inserting data with a valid relation', async () => {
@@ -852,7 +835,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
852
835
  expect(result.success).toBe(true);
853
836
  expect(result.insertedIds).toHaveLength(1);
854
837
  // Cleanup the created order for test isolation
855
- await deleteData(orderModel.name, result.insertedIds, {}, user);
838
+ await deleteData(orderModel.name, result.insertedIds, user);
856
839
  });
857
840
 
858
841
  it('should REJECT inserting data with a relation that does not respect the filter', async () => {
@@ -873,7 +856,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
873
856
  expect(result.modifiedCount).toBeGreaterThanOrEqual(0);
874
857
 
875
858
  // Cleanup
876
- await deleteData(orderModel.name, initialOrder.insertedIds, {}, user);
859
+ await deleteData(orderModel.name, initialOrder.insertedIds, user);
877
860
  });
878
861
 
879
862
  it('should REJECT updating data with a relation that does not respect the filter', async () => {
@@ -885,7 +868,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
885
868
  expect(result.success).toBe(false);
886
869
  expect(result.error).toContain('produit');
887
870
  // Cleanup
888
- await deleteData(orderModel.name, initialOrder.insertedIds, {}, user);
871
+ await deleteData(orderModel.name, initialOrder.insertedIds, user);
889
872
  });
890
873
  });
891
874
  });
@@ -299,7 +299,7 @@ describe('Intégration des Workflows - triggerWorkflows', () => {
299
299
  }, {}, mockUser, false);
300
300
 
301
301
  // 2. Act: Supprimer la donnée
302
- const deleteResult = await deleteData(targetDataModel.name, [projectId], {}, mockUser, true, true);
302
+ const deleteResult = await deleteData(targetDataModel.name, [projectId], mockUser, true, true);
303
303
  expect(deleteResult.success).toBe(true);
304
304
 
305
305
  // 3. Assert: Un `workflowRun` doit être créé