data-primals-engine 1.0.11 → 1.1.1

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.
Files changed (167) hide show
  1. package/README.md +36 -0
  2. package/client/README.md +116 -0
  3. package/client/index.html +31 -0
  4. package/client/index.js +25 -0
  5. package/client/package-lock.json +11664 -0
  6. package/client/package.json +70 -0
  7. package/client/public/demo/26899917-d1ba-4df4-bb33-48d09a8778da.jpg +0 -0
  8. package/client/public/demo/4b9894c7-12cd-466d-8fd3-a2757b09ec96.jpg +0 -0
  9. package/client/public/demo/7ed369ac-a1a2-4b45-b0cd-4fd5bcf5a75a.jpg +0 -0
  10. package/client/public/doc/API.postman_collection.json +214 -0
  11. package/client/public/github.svg +1 -0
  12. package/client/public/profilCompany.jpg +0 -0
  13. package/client/public/profilDeveloper.jpg +0 -0
  14. package/client/public/profilEngineer.jpg +0 -0
  15. package/client/public/profilPersonal.jpg +0 -0
  16. package/client/public/profils .psd +0 -0
  17. package/client/public/react.svg +9 -0
  18. package/client/src/APIInfo.jsx +328 -0
  19. package/client/src/AddWidgetTypeModal.jsx +44 -0
  20. package/client/src/AddWidgetTypeModal.scss +87 -0
  21. package/client/src/App.css +42 -0
  22. package/client/src/App.jsx +588 -0
  23. package/client/src/App.scss +1466 -0
  24. package/client/src/AssistantChat.jsx +280 -0
  25. package/client/src/AssistantChat.scss +229 -0
  26. package/client/src/Button.jsx +12 -0
  27. package/client/src/Button.scss +197 -0
  28. package/client/src/CalculationBuilder.jsx +338 -0
  29. package/client/src/CalculationStepRow.jsx +199 -0
  30. package/client/src/CalendarConfigModal.jsx +49 -0
  31. package/client/src/ChartConfigModal.jsx +402 -0
  32. package/client/src/ConditionBuilder.jsx +622 -0
  33. package/client/src/ConditionBuilder.scss +672 -0
  34. package/client/src/ConditionBuilder2.jsx +757 -0
  35. package/client/src/ContentView.jsx +274 -0
  36. package/client/src/CronBuilder.jsx +126 -0
  37. package/client/src/CronBuilder.scss +128 -0
  38. package/client/src/CronPartBuilder.jsx +150 -0
  39. package/client/src/Dashboard.jsx +210 -0
  40. package/client/src/Dashboard.scss +445 -0
  41. package/client/src/DashboardChart.jsx +362 -0
  42. package/client/src/DashboardFlexViewItem.jsx +129 -0
  43. package/client/src/DashboardView.jsx +554 -0
  44. package/client/src/DataChart.jsx +349 -0
  45. package/client/src/DataEditor.jsx +556 -0
  46. package/client/src/DataLayout.jsx +709 -0
  47. package/client/src/DataTable.jsx +996 -0
  48. package/client/src/DataTable.scss +73 -0
  49. package/client/src/Dialog.jsx +90 -0
  50. package/client/src/Dialog.scss +117 -0
  51. package/client/src/DisplayFlexNodeRenderer.jsx +115 -0
  52. package/client/src/DocumentationPageLayout.jsx +93 -0
  53. package/client/src/DocumentationPageLayout.scss +262 -0
  54. package/client/src/Draggable.jsx +222 -0
  55. package/client/src/Draggable.scss +49 -0
  56. package/client/src/ExportDialog.jsx +172 -0
  57. package/client/src/Field.jsx +1558 -0
  58. package/client/src/FlexBuilder.jsx +269 -0
  59. package/client/src/FlexBuilder.scss +226 -0
  60. package/client/src/FlexBuilderControls.jsx +170 -0
  61. package/client/src/FlexBuilderModal.jsx +75 -0
  62. package/client/src/FlexBuilderModal.scss +109 -0
  63. package/client/src/FlexBuilderPreview.jsx +48 -0
  64. package/client/src/FlexBuilderUtils.js +84 -0
  65. package/client/src/FlexDataRenderer.jsx +170 -0
  66. package/client/src/FlexDataRenderer.scss +80 -0
  67. package/client/src/FlexNode.jsx +290 -0
  68. package/client/src/FlexTreeUtils.js +129 -0
  69. package/client/src/HiddenableCell.jsx +46 -0
  70. package/client/src/HiddenableCell.scss +36 -0
  71. package/client/src/KPIDialog.jsx +39 -0
  72. package/client/src/KPIWidget.jsx +139 -0
  73. package/client/src/KanbanCard.jsx +92 -0
  74. package/client/src/KanbanColumn.jsx +29 -0
  75. package/client/src/KanbanConfigModal.jsx +115 -0
  76. package/client/src/KanbanView.jsx +113 -0
  77. package/client/src/KanbanView.scss +107 -0
  78. package/client/src/MessageRotator.jsx +77 -0
  79. package/client/src/MessageRotator.scss +14 -0
  80. package/client/src/ModelCreator.jsx +640 -0
  81. package/client/src/ModelCreator.scss +154 -0
  82. package/client/src/ModelCreatorField.jsx +810 -0
  83. package/client/src/ModelImporter.jsx +120 -0
  84. package/client/src/ModelList.jsx +205 -0
  85. package/client/src/Notification.jsx +137 -0
  86. package/client/src/Notification.scss +126 -0
  87. package/client/src/NotificationProvider.jsx +73 -0
  88. package/client/src/PackGallery.jsx +211 -0
  89. package/client/src/PackGallery.scss +156 -0
  90. package/client/src/Pagination.jsx +141 -0
  91. package/client/src/RTE.jsx +415 -0
  92. package/client/src/RTETrans.jsx +103 -0
  93. package/client/src/RelationField.jsx +247 -0
  94. package/client/src/RelationValue.jsx +230 -0
  95. package/client/src/RestoreConfirmationModal.jsx +183 -0
  96. package/client/src/RestoreDialog.jsx +134 -0
  97. package/client/src/RestoreDialog.scss +67 -0
  98. package/client/src/RichTextEditorModal.jsx +34 -0
  99. package/client/src/RichTextEditorModal.scss +54 -0
  100. package/client/src/TourSpotlight.jsx +234 -0
  101. package/client/src/TourSpotlight.scss +100 -0
  102. package/client/src/TutorialsMenu.jsx +83 -0
  103. package/client/src/TutorialsMenu.scss +217 -0
  104. package/client/src/TutorialsRewardModal.jsx +65 -0
  105. package/client/src/Utils.jsx +78 -0
  106. package/client/src/ViewSwitcher.jsx +54 -0
  107. package/client/src/ViewSwitcher.scss +74 -0
  108. package/client/src/Webpage.jsx +69 -0
  109. package/client/src/_variables.scss +21 -0
  110. package/client/src/assets/react.svg +1 -0
  111. package/client/src/constants.js +68 -0
  112. package/client/src/contexts/AuthContext.jsx +28 -0
  113. package/client/src/contexts/ModelContext.jsx +328 -0
  114. package/client/src/contexts/UIContext.jsx +52 -0
  115. package/client/src/core/data.js +35 -0
  116. package/client/src/entry-client.jsx +15 -0
  117. package/client/src/entry-server.jsx +13 -0
  118. package/client/src/filter.js +222 -0
  119. package/client/src/hooks/data.js +101 -0
  120. package/client/src/hooks/useDebounce.js +20 -0
  121. package/client/src/hooks/useDragAndDrop.js +59 -0
  122. package/client/src/hooks/useLocalStorage.js +100 -0
  123. package/client/src/hooks/useMount.js +42 -0
  124. package/client/src/hooks/useTutorials.jsx +227 -0
  125. package/client/src/hooks/useWindowSize.js +24 -0
  126. package/client/src/i18n.js +47 -0
  127. package/client/src/index.css +90 -0
  128. package/client/src/index.js +10 -0
  129. package/client/src/main.jsx +11 -0
  130. package/client/src/translations.js +15940 -0
  131. package/client/src/tutorials.js +112 -0
  132. package/client/vite.config.js +30 -0
  133. package/eslint.config.js +50 -0
  134. package/package.json +51 -27
  135. package/server.js +9 -0
  136. package/src/constants.js +12 -23
  137. package/src/core.js +9 -8
  138. package/src/data.js +81 -80
  139. package/src/defaultModels.js +114 -115
  140. package/src/email.js +8 -9
  141. package/src/engine.js +5 -5
  142. package/src/events.js +1 -2
  143. package/src/i18n.js +212 -211
  144. package/src/middlewares/middleware-mongodb.js +94 -93
  145. package/src/migrate.js +24 -24
  146. package/src/modules/assistant.js +55 -55
  147. package/src/modules/bucket.js +10 -9
  148. package/src/modules/data.js +387 -357
  149. package/src/modules/file.js +3 -6
  150. package/src/modules/mongodb.js +6 -7
  151. package/src/modules/user.js +24 -47
  152. package/src/modules/workflow.js +139 -73
  153. package/src/openai.jobs.js +2 -2
  154. package/src/packs.js +30 -31
  155. package/src/providers.js +101 -3
  156. package/src/setenv.js +1 -1
  157. package/src/user.js +0 -17
  158. package/src/workers/crypto-worker.js +21 -20
  159. package/src/workers/import-export-worker.js +18 -18
  160. package/test/data.backup.integration.test.js +7 -12
  161. package/test/data.integration.test.js +27 -25
  162. package/test/globalSetup.js +2 -2
  163. package/test/import_export.integration.test.js +6 -6
  164. package/test/model.integration.test.js +21 -22
  165. package/test/workflow.integration.test.js +2 -5
  166. package/test/workflow.robustness.test.js +6 -13
  167. package/vitest.config.js +2 -2
package/src/packs.js CHANGED
@@ -135,21 +135,20 @@ export const getAllPacks = async () => {
135
135
  }
136
136
  ],
137
137
  "dashboard": [{
138
- name: "Business Overview",
139
- description: "Displays the total revenue, total orders, and average order value of the store.",
140
- layout: [{
141
- "name": "Store Overview",
142
- "kpis": ["Total Orders", "Average Order Value", "Total Revenue"],
143
- "chartConfigs": [],
144
- "flexViews": []
145
- }],
146
- settings: {
147
- "defaultTimeRange": "last_7_days",
148
- "refreshInterval": null
149
- }
138
+ name: "Business Overview",
139
+ description: "Displays the total revenue, total orders, and average order value of the store.",
140
+ layout: [{
141
+ "name": "Store Overview",
142
+ "kpis": ["Total Orders", "Average Order Value", "Total Revenue"],
143
+ "chartConfigs": [],
144
+ "flexViews": []
145
+ }],
146
+ settings: {
147
+ "defaultTimeRange": "last_7_days",
148
+ "refreshInterval": null
150
149
  }
151
- ],
152
- "order": [
150
+ }],
151
+ "order": [
153
152
  {
154
153
  "orderId": "ORDER-0001",
155
154
  "orderDate": "2023-10-27T10:00:00Z",
@@ -275,13 +274,13 @@ export const getAllPacks = async () => {
275
274
  "name": "Validate Order",
276
275
  "workflow": { "$link": { "name": "Order Fulfillment", "_model": "workflow" } },
277
276
  "actions": { "$link": { "name": "Update order status to 'processing'", "_model": "workflowAction" } },
278
- "onSuccessStep": { "$link": { "name": "Prepare Shipment", "_model": "workflowStep" } },
277
+ "onSuccessStep": { "$link": { "name": "Prepare Shipment", "_model": "workflowStep" } }
279
278
  },
280
279
  {
281
280
  "name": "Prepare Shipment",
282
281
  "workflow": { "$link": { "name": "Order Fulfillment", "_model": "workflow" }},
283
282
  "actions": { "$link": { "name": "Create Shipment Record", "_model": "workflowAction" } },
284
- "onSuccessStep": { "$link": { "name": "Ship Order", "_model": "workflowStep" } },
283
+ "onSuccessStep": { "$link": { "name": "Ship Order", "_model": "workflowStep" } }
285
284
  },
286
285
  {
287
286
  "name": "Send Shipment Email Step",
@@ -296,7 +295,7 @@ export const getAllPacks = async () => {
296
295
  "$link": {
297
296
  "$or": [
298
297
  { "$eq": ["$name", "Update order status to 'shipped'"]},
299
- { "$eq": ["$name", "Send Shipping Confirmation"]},
298
+ { "$eq": ["$name", "Send Shipping Confirmation"]}
300
299
  ],
301
300
  "_model": "workflowAction"
302
301
  }
@@ -374,17 +373,17 @@ export const getAllPacks = async () => {
374
373
  type: 'category',
375
374
  parent: {
376
375
  "$find": {
377
- "name": "Website",
376
+ "name": "Website"
378
377
  }
379
378
  }
380
379
  })), ...tags.map(t =>({
381
380
  name: t,
382
- type: 'keyword',
381
+ type: 'keyword'
383
382
  }))],
384
383
  "permission": getPerms(['website', 'taxonomy', 'lang', 'user', 'role', 'permission']).map(m => {
385
384
  return {
386
385
  name: m,
387
- description: '',
386
+ description: ''
388
387
  }
389
388
  }),
390
389
  "role": roles.map(m => {
@@ -399,8 +398,8 @@ export const getAllPacks = async () => {
399
398
  }),
400
399
  "channel": [
401
400
  { "name": "Visitor alerts", "type": "web", "description": "Visitor main channel informations" },
402
- { "name": "Newsletter", "type": "email", "description": "Newsletter channel" },
403
- ],
401
+ { "name": "Newsletter", "type": "email", "description": "Newsletter channel" }
402
+ ]
404
403
  },
405
404
  "fr": {
406
405
  "lang": [{
@@ -408,8 +407,8 @@ export const getAllPacks = async () => {
408
407
  "code": "fr"
409
408
  }],
410
409
  "translation": [
411
- { "lang": { "$find": { "$eq": ["$code", "fr"]}}, "key": "Visitor alerts", "value": "Alertes visiteurs" },
412
- ],
410
+ { "lang": { "$find": { "$eq": ["$code", "fr"]}}, "key": "Visitor alerts", "value": "Alertes visiteurs" }
411
+ ]
413
412
  }
414
413
  }
415
414
  },
@@ -548,7 +547,7 @@ export const getAllPacks = async () => {
548
547
  { "lang": { "$link": { "code": "fr", "_model": "lang" } }, "key": "model_description_deal", "value": "Représente une opportunité commerciale avec un contact ou une entreprise." },
549
548
 
550
549
  { "lang": { "$link": { "code": "fr", "_model": "lang" } }, "key": "model_interaction", "value": "Interactions" },
551
- { "lang": { "$link": { "code": "fr", "_model": "lang" } }, "key": "model_description_interaction", "value": "Représente une interaction (appel, email, rdv) avec un contact ou une entreprise." },
550
+ { "lang": { "$link": { "code": "fr", "_model": "lang" } }, "key": "model_description_interaction", "value": "Représente une interaction (appel, email, rdv) avec un contact ou une entreprise." }
552
551
  ]
553
552
  },
554
553
  "en": {
@@ -595,7 +594,7 @@ export const getAllPacks = async () => {
595
594
  { "lang": { "$link": { "code": "en", "_model": "lang" } }, "key": "model_description_deal", "value": "Represents a business opportunity with a contact or company." },
596
595
 
597
596
  { "lang": { "$link": { "code": "en", "_model": "lang" } }, "key": "model_interaction", "value": "Interactions" },
598
- { "lang": { "$link": { "code": "en", "_model": "lang" } }, "key": "model_description_interaction", "value": "Represents an interaction (call, email, meeting) with a contact or company." },
597
+ { "lang": { "$link": { "code": "en", "_model": "lang" } }, "key": "model_description_interaction", "value": "Represents an interaction (call, email, meeting) with a contact or company." }
599
598
  ]
600
599
  },
601
600
  "it": {
@@ -1075,14 +1074,14 @@ export const getAllPacks = async () => {
1075
1074
  "type": "GenerateAIContent",
1076
1075
  "aiProvider": "OpenAI",
1077
1076
  "aiModel": "gpt-4o-mini",
1078
- "prompt": "Write a short, SEO-optimized product description (approximately 30-40 words) for the following product: '{triggerData.name}'. The description should be engaging and highlight the product. Return only the description text, without an introduction or conclusion.",
1077
+ "prompt": "Write a short, SEO-optimized product description (approximately 30-40 words) for the following product: '{triggerData.name}'. The description should be engaging and highlight the product. Return only the description text, without an introduction or conclusion."
1079
1078
  },
1080
1079
  {
1081
1080
  "name": "Generate SEO Description from Product (Google API)",
1082
1081
  "type": "GenerateAIContent",
1083
1082
  "aiProvider": "Google",
1084
1083
  "aiModel": "gemini-2.0-flash",
1085
- "prompt": "Write a short, SEO-optimized product description (approximately 30-40 words) for the following product: '{triggerData.name}'. The description should be engaging and highlight the product. Return only the description text, without an introduction or conclusion.",
1084
+ "prompt": "Write a short, SEO-optimized product description (approximately 30-40 words) for the following product: '{triggerData.name}'. The description should be engaging and highlight the product. Return only the description text, without an introduction or conclusion."
1086
1085
  },
1087
1086
  {
1088
1087
  "name": "Update Product with AI Description",
@@ -1100,7 +1099,7 @@ export const getAllPacks = async () => {
1100
1099
  "$find": {
1101
1100
  $or: [
1102
1101
  {"$eq": ["$name", "Generate SEO Description from Product (OpenAI API)"]},
1103
- {"$eq": ["$name", "Update Product with AI Description"]},
1102
+ {"$eq": ["$name", "Update Product with AI Description"]}
1104
1103
  ]
1105
1104
  }
1106
1105
  },
@@ -2300,7 +2299,7 @@ export const getAllPacks = async () => {
2300
2299
  { name:"Nouveau manat turkmène",code:"TMT", symbol: "m" },
2301
2300
  { name:"Som ouzbek",code:"UZS", symbol: "som" },
2302
2301
  { name:"Dong vietnamien",code:"VND", symbol: "₫" }
2303
- ],
2302
+ ]
2304
2303
  },
2305
2304
  "fr":{
2306
2305
  "lang": [{
@@ -3807,7 +3806,7 @@ export const getAllPacks = async () => {
3807
3806
  { "lang": { "$link": { "code": "sv", "_model": "lang" } }, "key": "Som ouzbek", "value": "Uzbekisk sum" },
3808
3807
  { "lang": { "$link": { "code": "sv", "_model": "lang" } }, "key": "Dong vietnamien", "value": "Vietnamesisk dong" }
3809
3808
  ]
3810
- },
3809
+ }
3811
3810
 
3812
3811
  }
3813
3812
  }
package/src/providers.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {compare} from "bcrypt";
2
+ import {maxTotalPrivateFilesSize} from "./constants.js";
2
3
 
3
4
  /**
4
5
  * @class UserProvider
@@ -6,11 +7,15 @@ import {compare} from "bcrypt";
6
7
  * C'est une classe de base abstraite, elle n'est pas destinée à être utilisée directement.
7
8
  */
8
9
  export class UserProvider {
10
+
11
+ plans = {};
12
+
9
13
  constructor(engine) {
10
14
  if (this.constructor === UserProvider) {
11
15
  throw new Error("Abstract classes can't be instantiated.");
12
16
  }
13
17
  this.engine = engine;
18
+ this.plans = this.getUserPlans();
14
19
  }
15
20
 
16
21
  /**
@@ -50,6 +55,45 @@ export class UserProvider {
50
55
  throw new Error("Method 'initiateUser()' must be implemented.");
51
56
  }
52
57
 
58
+ /**
59
+ * Récupère la limite de stockage d'un utilisateur.
60
+ * @param user
61
+ * @returns {Promise<number>}
62
+ */
63
+ async getUserStorageLimit(user) {
64
+ return maxTotalPrivateFilesSize;
65
+ }
66
+
67
+ /**
68
+ * Récupère la fréquence de sauvegarde d'un utilisateur.
69
+ * @param user
70
+ * @returns {Promise<void>}
71
+ */
72
+ async getBackupFrequency(user){
73
+ return 'daily';
74
+ }
75
+
76
+ /**
77
+ * Récupère les middlewares d'un utilisateur.
78
+ * @returns {Promise<*[]>}
79
+ */
80
+ async getMiddlewares(){
81
+ return [];
82
+ }
83
+
84
+ getUserPlans(){
85
+ return {
86
+ free: {
87
+ requestLimitPerHour: 10000,
88
+ features: ['indexes'] // Feature list : indexes is the only option for now. Use a dedicated collection for this user
89
+ }
90
+ };
91
+ }
92
+
93
+ async hasFeature(user, feature) {
94
+ return this.plans[user.userPlan]?.features.some(f => f === feature);
95
+ }
96
+
53
97
  // Ajoutez ici d'autres méthodes nécessaires : findUserById, createUser, etc.
54
98
  }
55
99
 
@@ -58,19 +102,73 @@ export class DefaultUserProvider extends UserProvider {
58
102
 
59
103
  users= [{ username: "demo", password: "demo" }];
60
104
 
105
+ /**
106
+ * Trouve un utilisateur. Gère spécifiquement les utilisateurs de démo.
107
+ */
61
108
  async findUserByUsername(username) {
109
+ // Si le nom d'utilisateur commence par "demo", on le considère comme un utilisateur de démo valide et volatile.
110
+ if (typeof username === 'string' && username.startsWith('demo')) {
111
+ // On retourne un objet utilisateur de démo avec la structure attendue.
112
+ return { username: username, password: "demo", userPlan: 'free' }; // Ajout de userPlan pour la cohérence
113
+ }
114
+ // Logique pour les vrais utilisateurs (si vous en ajoutez plus tard)
62
115
  return this.users.find(user => user.username === username);
63
116
  }
64
117
 
118
+ async getUserStorageLimit(user) {
119
+ return maxTotalPrivateFilesSize;
120
+ }
121
+
122
+ async getBackupFrequency(user){
123
+ return 'daily';
124
+ }
125
+
126
+ async getMiddlewares(){
127
+ return []
128
+ }
129
+
65
130
  async validatePassword(user, password) {
66
- return true;
131
+ // Pour un utilisateur de démo, le mot de passe est toujours valide.
132
+ if (user.username.startsWith('demo')) {
133
+ return true;
134
+ }
135
+ // Logique pour les vrais utilisateurs
136
+ return true; // ou votre logique de comparaison bcrypt
67
137
  }
68
138
 
69
139
  async updateUser(user, data) {
70
140
  this.users = this.users.map(user => user.username === user.username ? {...user, ...data} : user);
71
141
  }
72
-
142
+ /**
143
+ * Initialise l'utilisateur sur la requête. C'est ici que la magie opère.
144
+ */
73
145
  async initiateUser(req) {
74
- req.me = this.users[0];
146
+ // Priorité 1: Un utilisateur est déjà authentifié via une session (pour les vrais comptes).
147
+ if (req.session?.user?.username) {
148
+ const user = await this.findUserByUsername(req.session.user.username);
149
+ if (user) {
150
+ req.me = user;
151
+ return; // L'utilisateur est trouvé, on s'arrête là.
152
+ }
153
+ }
154
+
155
+ // Priorité 2: PasF de session, mais on vérifie la présence d'un cookie "username" pour la démo.
156
+ const demoUsername = req.cookies?.username;
157
+ if (demoUsername && typeof demoUsername === 'string' && demoUsername.startsWith('demo')) {
158
+ // On a trouvé un cookie de démo. On crée l'objet utilisateur correspondant.
159
+ const demoUser = await this.findUserByUsername(demoUsername);
160
+ if (demoUser) {
161
+ req.me = demoUser;
162
+ return;
163
+ }
164
+ }
165
+ }
166
+
167
+ getUserPlans(){
168
+ return {
169
+ free: {
170
+ features: ['indexes']
171
+ }
172
+ }
75
173
  }
76
174
  }
package/src/setenv.js CHANGED
@@ -2,7 +2,7 @@ import {getRandom} from "data-primals-engine/core";
2
2
  import process from "node:process";
3
3
  import {Engine} from "./index.js";
4
4
 
5
- let ports = [], engineInstance, mongod;
5
+ let ports = [], engineInstance;
6
6
  export const getUniquePort = () =>{
7
7
  let d, it=0;
8
8
  do{
package/src/user.js CHANGED
@@ -1,17 +0,0 @@
1
- import {
2
- maxTotalPrivateFilesSizeFree,
3
- maxTotalPrivateFilesSizePremium,
4
- maxTotalPrivateFilesSizeStandard
5
- } from "./constants.js";
6
-
7
- export const getUserStorageLimit = (user) => {
8
- switch (user.userPlan) {
9
- case 'premium':
10
- return maxTotalPrivateFilesSizePremium;
11
- case 'standard':
12
- return maxTotalPrivateFilesSizeStandard;
13
- case 'free':
14
- default:
15
- return maxTotalPrivateFilesSizeFree;
16
- }
17
- };
@@ -46,29 +46,30 @@ parentPort.on('message', async ({ action, payload }) => {
46
46
  try {
47
47
  let result;
48
48
  switch (action) {
49
- case 'encrypt':
50
- console.log(`[Worker] Received action: ${action} for file: ${payload.filePath}`);
51
- await encryptFile(payload.filePath, payload.password);
52
- parentPort.postMessage({ success: true }); // Pas de données à retourner
53
- break;
49
+ case 'encrypt':
50
+ console.log(`[Worker] Received action: ${action} for file: ${payload.filePath}`);
51
+ await encryptFile(payload.filePath, payload.password);
52
+ parentPort.postMessage({ success: true }); // Pas de données à retourner
53
+ break;
54
54
 
55
- case 'decrypt':
56
- console.log(`[Worker] Received action: ${action} for file: ${payload.filePath}`);
57
- await decryptFile(payload.filePath, payload.password);
58
- parentPort.postMessage({ success: true }); // Pas de données à retourner
59
- break;
55
+ case 'decrypt':
56
+ console.log(`[Worker] Received action: ${action} for file: ${payload.filePath}`);
57
+ await decryptFile(payload.filePath, payload.password);
58
+ parentPort.postMessage({ success: true }); // Pas de données à retourner
59
+ break;
60
+
60
61
 
61
- case 'hash':
62
- console.log(`[Worker] Received action: hash`);
63
- if (!payload.data) throw new Error('Data to hash is missing in payload.');
64
- // Le worker gère à la fois la génération du "salt" et le hachage
65
- const salt = await bcrypt.genSalt(10);
66
- result = await bcrypt.hash(payload.data, salt);
67
- parentPort.postMessage({ success: true, data: result }); // On retourne le hash
68
- break;
62
+ case 'hash':
63
+ console.log(`[Worker] Received action: hash`);
64
+ if (!payload.data) throw new Error('Data to hash is missing in payload.');
65
+ // Le worker gère à la fois la génération du "salt" et le hachage
66
+ const salt = await bcrypt.genSalt(10);
67
+ result = await bcrypt.hash(payload.data, salt);
68
+ parentPort.postMessage({ success: true, data: result }); // On retourne le hash
69
+ break;
69
70
 
70
- default:
71
- throw new Error(`Unknown crypto action: ${action}`);
71
+ default:
72
+ throw new Error(`Unknown crypto action: ${action}`);
72
73
  }
73
74
  } catch (error) {
74
75
  // Envoie l'erreur au thread principal
@@ -5,27 +5,27 @@ parentPort.on('message', ({ action, payload }) => {
5
5
  try {
6
6
  let result;
7
7
  switch (action) {
8
- case 'parse-json':
9
- // Tâche: Parser une chaîne/buffer JSON en objet JS
10
- result = JSON.parse(payload.fileContent.toString('utf-8'));
11
- break;
8
+ case 'parse-json':
9
+ // Tâche: Parser une chaîne/buffer JSON en objet JS
10
+ result = JSON.parse(payload.fileContent.toString('utf-8'));
11
+ break;
12
12
 
13
- case 'parse-csv':
14
- // Tâche: Parser une chaîne/buffer CSV en tableau d'objets JS
15
- result = parse(payload.fileContent, {
16
- columns: payload.options.columns,
17
- skip_empty_lines: true,
18
- trim: true,
19
- });
20
- break;
13
+ case 'parse-csv':
14
+ // Tâche: Parser une chaîne/buffer CSV en tableau d'objets JS
15
+ result = parse(payload.fileContent, {
16
+ columns: payload.options.columns,
17
+ skip_empty_lines: true,
18
+ trim: true
19
+ });
20
+ break;
21
21
 
22
- case 'stringify-json':
23
- // Tâche: Sérialiser un objet/tableau JS en chaîne JSON
24
- result = JSON.stringify(payload.data);
25
- break;
22
+ case 'stringify-json':
23
+ // Tâche: Sérialiser un objet/tableau JS en chaîne JSON
24
+ result = JSON.stringify(payload.data);
25
+ break;
26
26
 
27
- default:
28
- throw new Error(`Unknown action: ${action}`);
27
+ default:
28
+ throw new Error(`Unknown action: ${action}`);
29
29
  }
30
30
  // Renvoyer le résultat au thread principal
31
31
  parentPort.postMessage({ success: true, data: result });
@@ -6,25 +6,21 @@ import { Config } from '../src/config.js';
6
6
  import { ObjectId } from 'mongodb';
7
7
  import {expect, describe, it, beforeAll, afterAll, beforeEach} from 'vitest';
8
8
  import { vi } from 'vitest'
9
- import { Buffer } from 'node:buffer'; // Explicitly import Buffer
10
- import crypto from 'node:crypto'; //Explicitly import crypto
11
9
 
12
10
  import {
13
11
  createModel,
14
- getModel, insertData
12
+ insertData
15
13
  } from 'data-primals-engine/modules/data';
16
14
 
17
15
  import {
18
16
  modelsCollection as getAppModelsCollection,
19
- getCollectionForUser as getAppUserCollection,
17
+ getCollectionForUser as getAppUserCollection
20
18
  } from 'data-primals-engine/modules/mongodb';
21
- import { Engine } from "data-primals-engine/engine";
22
19
  import process from "node:process";
23
20
 
24
- import { dumpUserData, loadFromDump, getUserHash } from 'data-primals-engine/modules/data';
21
+ import { dumpUserData, loadFromDump } from 'data-primals-engine/modules/data';
25
22
  import fs from "node:fs";
26
- import {getRandom} from "data-primals-engine/core";
27
- import {getUniquePort, initEngine, stopEngine} from "../src/setenv.js";
23
+ import {initEngine} from "../src/setenv.js";
28
24
 
29
25
  vi.mock('data-primals-engine/engine', async(importOriginal) => {
30
26
  const mod = await importOriginal() // type is inferred
@@ -37,7 +33,6 @@ vi.mock('data-primals-engine/engine', async(importOriginal) => {
37
33
  const mockUser = {
38
34
  username: 'testuserBackup',
39
35
  _user: 'testuserBackup',
40
- userPlan: 'premium',
41
36
  email: 'testBackup@example.com',
42
37
  configS3: {
43
38
  bucketName: null
@@ -50,9 +45,9 @@ const testModelDefinition = {
50
45
  description: 'Model for testing backup/restore',
51
46
  fields: [
52
47
  { name: 'testField', type: 'string', required: true },
53
- { name: 'optionalField', type: 'number' },
48
+ { name: 'optionalField', type: 'number' }
54
49
  ],
55
- maxRequestData: 10,
50
+ maxRequestData: 10
56
51
  };
57
52
 
58
53
  let testModelsColInstance;
@@ -101,7 +96,7 @@ beforeAll(async () =>{
101
96
  })
102
97
  beforeEach(async () => {
103
98
  testModelsColInstance = getAppModelsCollection;
104
- testDatasColInstance = getAppUserCollection(mockUser);
99
+ testDatasColInstance = await getAppUserCollection(mockUser);
105
100
  });
106
101
 
107
102
  describe('Data Backup and Restore Integration', () => {
@@ -14,8 +14,7 @@ import {
14
14
  import {
15
15
  modelsCollection as getAppModelsCollection,
16
16
  getCollection,
17
- getCollectionForUser as getAppUserCollection,
18
- datasCollection // Accès direct pour vérifications
17
+ getCollectionForUser as getAppUserCollection
19
18
  } from 'data-primals-engine/modules/mongodb';
20
19
  import { Engine } from "data-primals-engine/engine";
21
20
  import process from "node:process";
@@ -41,6 +40,9 @@ async function setupTestContext() {
41
40
  email: generateUniqueName('test') + '@example.com'
42
41
  };
43
42
 
43
+ // Initialize collection instances after the engine is ready
44
+ testModelsColInstance = getAppModelsCollection;
45
+ testDatasColInstance = await getAppUserCollection(currentTestUser);
44
46
 
45
47
  const relatedModelDefinition = {
46
48
  name: currentRelatedModelName,
@@ -50,7 +52,7 @@ async function setupTestContext() {
50
52
  {name: 'relatedName', type: 'string', required: true, unique: true},
51
53
  {name: 'relatedValue', type: 'number'}
52
54
  ],
53
- maxRequestData: 10,
55
+ maxRequestData: 10
54
56
  };
55
57
 
56
58
  const comprehensiveTestModelDefinition = {
@@ -102,23 +104,25 @@ async function setupTestContext() {
102
104
  {name: 'objectField', type: 'object'},
103
105
  // Model & ModelField (validation of string format, not existence)
104
106
  {name: 'modelNameField', type: 'model'},
105
- {name: 'modelFieldNameField', type: 'modelField'}, // Note: modelField type expects an object {model: 'modelName', field: 'fieldName'}
107
+ {name: 'modelFieldNameField', type: 'modelField'} // Note: modelField type expects an object {model: 'modelName', field: 'fieldName'}
106
108
  ],
107
- maxRequestData: 50,
109
+ maxRequestData: 50
108
110
  };
109
111
 
110
- // Insérer les modèles en base
111
- await testModelsColInstance.insertMany([
112
- comprehensiveTestModelDefinition,
113
- relatedModelDefinition
114
- ]);
112
+ if( await testModelsColInstance.find({ $or: [{name: comprehensiveTestModelDefinition.name}, {name: relatedModelDefinition.name}]})) {
113
+ // Insérer les modèles en base
114
+ await testModelsColInstance.insertMany([
115
+ comprehensiveTestModelDefinition,
116
+ relatedModelDefinition
117
+ ]);
118
+ }
115
119
  await testDatasColInstance.deleteMany({ _user: currentTestUser.username });
116
120
 
117
121
  // Retourner toutes les variables nécessaires pour un test
118
122
  return {
119
123
  currentTestUser,
120
124
  comprehensiveTestModelDefinition,
121
- relatedModelDefinition,
125
+ relatedModelDefinition
122
126
  };
123
127
  }
124
128
 
@@ -128,9 +132,6 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
128
132
  Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant"]);
129
133
  await initEngine();
130
134
 
131
- // Initialize collection instances after the engine is ready
132
- testModelsColInstance = getAppModelsCollection;
133
- testDatasColInstance = datasCollection;
134
135
  })
135
136
 
136
137
  describe('insertData avec comprehensiveTestModel', () => {
@@ -186,13 +187,14 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
186
187
  codeJsField: 'console.log("hello");',
187
188
  objectField: { a: 1, b: "test" },
188
189
  modelNameField: 'someModelName',
189
- modelFieldNameField: { model: 'someModelName', field: 'someFieldName' },
190
+ modelFieldNameField: { model: 'someModelName', field: 'someFieldName' }
190
191
  };
191
192
 
192
193
  const result = await insertData(comprehensiveTestModelDefinition.name, validData, {}, currentTestUser, false);
193
194
  expect(result.success, `L'insertion principale a échoué: ${result.error}`).toBe(true);
194
195
  expect(result.insertedIds).toHaveLength(1);
195
196
 
197
+ console.log(result);
196
198
  const insertedDoc = await testDatasColInstance.findOne({ _id: new ObjectId(result.insertedIds[0]) });
197
199
  expect(insertedDoc).not.toBeNull();
198
200
  expect(insertedDoc.stringRequired).toBe('Valid String');
@@ -365,7 +367,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
365
367
  codeJsField: 'console.log("find");',
366
368
  objectField: { find: "test" },
367
369
  modelNameField: 'findModel',
368
- modelFieldNameField: { model: 'findModel', field: 'findField' },
370
+ modelFieldNameField: { model: 'findModel', field: 'findField' }
369
371
  };
370
372
 
371
373
  // 3. Insérer le document principal
@@ -411,7 +413,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
411
413
  stringUnique: 'UniqueForEdit',
412
414
  enumField: 'alpha',
413
415
  passwordField: 'initialPass',
414
- relationSingle: relatedDocId,
416
+ relationSingle: relatedDocId
415
417
  };
416
418
  const insertResult = await insertData(comprehensiveTestModelDefinition.name, initialData, {}, currentTestUser, false);
417
419
  docToEditId = insertResult.insertedIds[0];
@@ -493,17 +495,17 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
493
495
  await insertData(simpleModel.name, { name: 'Autre Item', value: 403 }, {}, currentTestUser, false);
494
496
 
495
497
  const filter = { $regexMatch: {
496
- input: '$name',
497
- regex: "^Item Filtrable"
498
- } };
498
+ input: '$name',
499
+ regex: "^Item Filtrable"
500
+ } };
499
501
  const deleteResult = await deleteData(simpleModel.name, [], filter, currentTestUser, false);
500
502
 
501
503
  expect(deleteResult.success).toBe(true);
502
504
  expect(deleteResult.deletedCount).toBe(2);
503
505
 
504
- const remainingCount = await testDatasColInstance.countDocuments({ _model: simpleModel.name, name: { $regex: "^Item Filtrable" } });
506
+ const remainingCount = await testDatasColInstance.countDocuments({ _user: currentTestUser.username, _model: simpleModel.name, name: { $regex: "^Item Filtrable" } });
505
507
  expect(remainingCount).toBe(0);
506
- const totalRemaining = await testDatasColInstance.countDocuments({ _model: simpleModel.name });
508
+ const totalRemaining = await testDatasColInstance.countDocuments({ _user: currentTestUser.username, _model: simpleModel.name });
507
509
  expect(totalRemaining).toBe(1);
508
510
  });
509
511
  });
@@ -531,7 +533,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
531
533
  passwordField: 'searchPass1',
532
534
  relationSingle: relatedDocId_A1,
533
535
  relationMultiple: [relatedDocId_A1, relatedDocId_A2],
534
- number: 10,
536
+ number: 10
535
537
  };
536
538
  const insertResult1 = await insertData(comprehensiveTestModelDefinition.name, data1, {}, currentTestUser, false);
537
539
  docId1 = insertResult1.insertedIds[0].toString();
@@ -543,7 +545,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
543
545
  passwordField: 'searchPass2',
544
546
  relationSingle: relatedDocId_B1,
545
547
  relationMultiple: [relatedDocId_B1],
546
- number: 20,
548
+ number: 20
547
549
  };
548
550
  const insertResult2 = await insertData(comprehensiveTestModelDefinition.name, data2, {}, currentTestUser, false);
549
551
  docId2 = insertResult2.insertedIds[0].toString();
@@ -564,7 +566,7 @@ describe('Intégration des fonctions CRUD de données avec validation complète'
564
566
  },
565
567
  autoExpand: true,
566
568
  depth: 8
567
- },
569
+ }
568
570
  };
569
571
  const { data, count } = await searchData(searchParams);
570
572
  expect(count).toBe(1);