data-primals-engine 1.0.11 → 1.1.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.
- package/client/README.md +8 -0
- package/client/index.html +31 -0
- package/client/index.js +25 -0
- package/client/package-lock.json +11664 -0
- package/client/package.json +70 -0
- package/client/public/demo/26899917-d1ba-4df4-bb33-48d09a8778da.jpg +0 -0
- package/client/public/demo/4b9894c7-12cd-466d-8fd3-a2757b09ec96.jpg +0 -0
- package/client/public/demo/7ed369ac-a1a2-4b45-b0cd-4fd5bcf5a75a.jpg +0 -0
- package/client/public/doc/API.postman_collection.json +214 -0
- package/client/public/github.svg +1 -0
- package/client/public/profilCompany.jpg +0 -0
- package/client/public/profilDeveloper.jpg +0 -0
- package/client/public/profilEngineer.jpg +0 -0
- package/client/public/profilPersonal.jpg +0 -0
- package/client/public/profils .psd +0 -0
- package/client/public/react.svg +9 -0
- package/client/src/APIInfo.jsx +328 -0
- package/client/src/AddWidgetTypeModal.jsx +44 -0
- package/client/src/AddWidgetTypeModal.scss +87 -0
- package/client/src/App.css +42 -0
- package/client/src/App.jsx +586 -0
- package/client/src/App.scss +1466 -0
- package/client/src/AssistantChat.jsx +280 -0
- package/client/src/AssistantChat.scss +229 -0
- package/client/src/Button.jsx +12 -0
- package/client/src/Button.scss +197 -0
- package/client/src/CalculationBuilder.jsx +338 -0
- package/client/src/CalculationStepRow.jsx +199 -0
- package/client/src/CalendarConfigModal.jsx +49 -0
- package/client/src/ChartConfigModal.jsx +402 -0
- package/client/src/ConditionBuilder.jsx +622 -0
- package/client/src/ConditionBuilder.scss +672 -0
- package/client/src/ConditionBuilder2.jsx +757 -0
- package/client/src/ContentView.jsx +274 -0
- package/client/src/CronBuilder.jsx +126 -0
- package/client/src/CronBuilder.scss +128 -0
- package/client/src/CronPartBuilder.jsx +150 -0
- package/client/src/Dashboard.jsx +210 -0
- package/client/src/Dashboard.scss +445 -0
- package/client/src/DashboardChart.jsx +362 -0
- package/client/src/DashboardFlexViewItem.jsx +129 -0
- package/client/src/DashboardView.jsx +554 -0
- package/client/src/DataChart.jsx +349 -0
- package/client/src/DataEditor.jsx +556 -0
- package/client/src/DataLayout.jsx +709 -0
- package/client/src/DataTable.jsx +996 -0
- package/client/src/DataTable.scss +73 -0
- package/client/src/Dialog.jsx +90 -0
- package/client/src/Dialog.scss +117 -0
- package/client/src/DisplayFlexNodeRenderer.jsx +115 -0
- package/client/src/DocumentationPageLayout.jsx +93 -0
- package/client/src/DocumentationPageLayout.scss +262 -0
- package/client/src/Draggable.jsx +222 -0
- package/client/src/Draggable.scss +49 -0
- package/client/src/ExportDialog.jsx +172 -0
- package/client/src/Field.jsx +1558 -0
- package/client/src/FlexBuilder.jsx +269 -0
- package/client/src/FlexBuilder.scss +226 -0
- package/client/src/FlexBuilderControls.jsx +170 -0
- package/client/src/FlexBuilderModal.jsx +75 -0
- package/client/src/FlexBuilderModal.scss +109 -0
- package/client/src/FlexBuilderPreview.jsx +48 -0
- package/client/src/FlexBuilderUtils.js +84 -0
- package/client/src/FlexDataRenderer.jsx +170 -0
- package/client/src/FlexDataRenderer.scss +80 -0
- package/client/src/FlexNode.jsx +290 -0
- package/client/src/FlexTreeUtils.js +129 -0
- package/client/src/HiddenableCell.jsx +46 -0
- package/client/src/HiddenableCell.scss +36 -0
- package/client/src/KPIDialog.jsx +39 -0
- package/client/src/KPIWidget.jsx +139 -0
- package/client/src/KanbanCard.jsx +92 -0
- package/client/src/KanbanColumn.jsx +29 -0
- package/client/src/KanbanConfigModal.jsx +115 -0
- package/client/src/KanbanView.jsx +113 -0
- package/client/src/KanbanView.scss +107 -0
- package/client/src/MessageRotator.jsx +77 -0
- package/client/src/MessageRotator.scss +14 -0
- package/client/src/ModelCreator.jsx +640 -0
- package/client/src/ModelCreator.scss +154 -0
- package/client/src/ModelCreatorField.jsx +810 -0
- package/client/src/ModelImporter.jsx +120 -0
- package/client/src/ModelList.jsx +205 -0
- package/client/src/Notification.jsx +137 -0
- package/client/src/Notification.scss +126 -0
- package/client/src/NotificationProvider.jsx +73 -0
- package/client/src/PackGallery.jsx +211 -0
- package/client/src/PackGallery.scss +156 -0
- package/client/src/Pagination.jsx +141 -0
- package/client/src/RTE.jsx +415 -0
- package/client/src/RTETrans.jsx +103 -0
- package/client/src/RelationField.jsx +247 -0
- package/client/src/RelationValue.jsx +230 -0
- package/client/src/RestoreConfirmationModal.jsx +183 -0
- package/client/src/RestoreDialog.jsx +134 -0
- package/client/src/RestoreDialog.scss +67 -0
- package/client/src/RichTextEditorModal.jsx +34 -0
- package/client/src/RichTextEditorModal.scss +54 -0
- package/client/src/TourSpotlight.jsx +234 -0
- package/client/src/TourSpotlight.scss +100 -0
- package/client/src/TutorialsMenu.jsx +83 -0
- package/client/src/TutorialsMenu.scss +217 -0
- package/client/src/TutorialsRewardModal.jsx +65 -0
- package/client/src/Utils.jsx +78 -0
- package/client/src/ViewSwitcher.jsx +54 -0
- package/client/src/ViewSwitcher.scss +74 -0
- package/client/src/Webpage.jsx +69 -0
- package/client/src/_variables.scss +21 -0
- package/client/src/assets/react.svg +1 -0
- package/client/src/constants.js +68 -0
- package/client/src/contexts/AuthContext.jsx +28 -0
- package/client/src/contexts/ModelContext.jsx +328 -0
- package/client/src/contexts/UIContext.jsx +52 -0
- package/client/src/core/data.js +35 -0
- package/client/src/entry-client.jsx +15 -0
- package/client/src/entry-server.jsx +13 -0
- package/client/src/filter.js +222 -0
- package/client/src/hooks/data.js +101 -0
- package/client/src/hooks/useDebounce.js +20 -0
- package/client/src/hooks/useDragAndDrop.js +59 -0
- package/client/src/hooks/useLocalStorage.js +100 -0
- package/client/src/hooks/useMount.js +42 -0
- package/client/src/hooks/useTutorials.jsx +227 -0
- package/client/src/hooks/useWindowSize.js +24 -0
- package/client/src/i18n.js +47 -0
- package/client/src/index.css +90 -0
- package/client/src/index.js +10 -0
- package/client/src/main.jsx +11 -0
- package/client/src/translations.js +15940 -0
- package/client/src/tutorials.js +112 -0
- package/client/vite.config.js +30 -0
- package/eslint.config.js +50 -0
- package/package.json +48 -27
- package/server.js +9 -0
- package/src/constants.js +12 -23
- package/src/core.js +9 -8
- package/src/data.js +81 -80
- package/src/defaultModels.js +114 -115
- package/src/email.js +8 -9
- package/src/engine.js +5 -5
- package/src/events.js +1 -2
- package/src/i18n.js +212 -211
- package/src/middlewares/middleware-mongodb.js +94 -93
- package/src/migrate.js +24 -24
- package/src/modules/assistant.js +55 -55
- package/src/modules/bucket.js +10 -9
- package/src/modules/data.js +387 -357
- package/src/modules/file.js +3 -6
- package/src/modules/mongodb.js +6 -7
- package/src/modules/user.js +24 -47
- package/src/modules/workflow.js +68 -67
- package/src/openai.jobs.js +2 -2
- package/src/packs.js +30 -31
- package/src/providers.js +101 -3
- package/src/setenv.js +1 -1
- package/src/user.js +0 -17
- package/src/workers/crypto-worker.js +21 -20
- package/src/workers/import-export-worker.js +18 -18
- package/test/data.backup.integration.test.js +7 -12
- package/test/data.integration.test.js +27 -25
- package/test/globalSetup.js +2 -2
- package/test/import_export.integration.test.js +6 -6
- package/test/model.integration.test.js +21 -22
- package/test/workflow.integration.test.js +2 -5
- package/test/workflow.robustness.test.js +6 -13
- package/vitest.config.js +2 -2
package/src/modules/file.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import {maxPrivateFileSize, megabytes} from "../constants.js";
|
|
4
4
|
import {isLocalUser} from "../data.js";
|
|
5
5
|
import i18n from "data-primals-engine/i18n";
|
|
6
|
-
import {getUserStorageLimit} from "../user.js";
|
|
7
6
|
import {getCollection} from "./mongodb.js";
|
|
8
7
|
import {getFileExtension, isGUID, uuidv4} from "../core.js";
|
|
9
8
|
import path from "node:path";
|
|
@@ -14,9 +13,6 @@ import crypto from "node:crypto";
|
|
|
14
13
|
import * as tar from "tar";
|
|
15
14
|
import {promisify} from "node:util";
|
|
16
15
|
import {calculateTotalUserStorageUsage, hasPermission} from "./user.js";
|
|
17
|
-
import {Logger} from "../gameObject.js";
|
|
18
|
-
import YAML from "yaml";
|
|
19
|
-
import swaggerUi from "swagger-ui-express";
|
|
20
16
|
|
|
21
17
|
const pbkdf2Async = promisify(crypto.pbkdf2);
|
|
22
18
|
|
|
@@ -56,7 +52,7 @@ export const addFile = async (file, user) => {
|
|
|
56
52
|
|
|
57
53
|
const incomingDataSize = file.size;
|
|
58
54
|
|
|
59
|
-
const userStorageLimit = getUserStorageLimit(user);
|
|
55
|
+
const userStorageLimit = await engine.userProvider.getUserStorageLimit(user);
|
|
60
56
|
const currentStorageUsage = await calculateTotalUserStorageUsage(user);
|
|
61
57
|
|
|
62
58
|
if (currentStorageUsage + incomingDataSize > userStorageLimit) {
|
|
@@ -194,6 +190,7 @@ export async function decryptFile(filePath, password) {
|
|
|
194
190
|
}
|
|
195
191
|
}
|
|
196
192
|
|
|
193
|
+
let engine;
|
|
197
194
|
export async function onInit(defaultEngine) {
|
|
198
|
-
|
|
195
|
+
engine = defaultEngine;
|
|
199
196
|
}
|
package/src/modules/mongodb.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import process from "process";
|
|
3
|
-
import {MongoClient as InternalMongoClient} from "mongodb";
|
|
4
3
|
import {Logger} from "../gameObject.js";
|
|
5
|
-
import {
|
|
6
|
-
import * as tls from "node:tls";
|
|
4
|
+
import {MongoDatabase} from "../engine.js";
|
|
7
5
|
import fs from "node:fs";
|
|
8
6
|
|
|
9
7
|
export let modelsCollection, datasCollection, filesCollection, packsCollection;
|
|
@@ -46,14 +44,15 @@ export const getCollection = (str) => {
|
|
|
46
44
|
|
|
47
45
|
|
|
48
46
|
// New function to determine the collection name for a user
|
|
49
|
-
export const getUserCollectionName = (user) => {
|
|
50
|
-
|
|
47
|
+
export const getUserCollectionName = async (user) => {
|
|
48
|
+
const feat = await engine.userProvider.hasFeature(user, 'indexes');
|
|
49
|
+
return feat ? `datas_${user.username}` : 'datas';
|
|
51
50
|
};
|
|
52
51
|
|
|
53
52
|
|
|
54
53
|
// Modify existing functions to use the correct collection
|
|
55
|
-
export const getCollectionForUser = (user) => {
|
|
56
|
-
const collectionName = getUserCollectionName(user);
|
|
54
|
+
export const getCollectionForUser = async (user) => {
|
|
55
|
+
const collectionName = await getUserCollectionName(user);
|
|
57
56
|
return getCollection(collectionName);
|
|
58
57
|
};
|
|
59
58
|
|
package/src/modules/user.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import i18n from "data-primals-engine/i18n";
|
|
2
|
-
import {
|
|
2
|
+
import {MongoDatabase} from "../engine.js";
|
|
3
3
|
import {getCollection, getCollectionForUser, getUserCollectionName} from "./mongodb.js";
|
|
4
|
-
import {dbName, plans} from "../constants.js";
|
|
5
4
|
import {isLocalUser} from "../data.js";
|
|
6
5
|
import {ObjectId} from "mongodb";
|
|
7
6
|
import {getAPILang} from "./data.js";
|
|
@@ -20,10 +19,10 @@ export const userInitiator = async (req, res, next) => {
|
|
|
20
19
|
// set current lang for user
|
|
21
20
|
i18n.changeLanguage(lang);
|
|
22
21
|
|
|
23
|
-
if (req.me
|
|
22
|
+
if (await engine.userProvider.hasFeature(req.me, 'indexes')) {
|
|
24
23
|
const collections = await MongoDatabase.listCollections().toArray();
|
|
25
24
|
const collectionNames = collections.map(c => c.name);
|
|
26
|
-
const coll = getUserCollectionName(req.me);
|
|
25
|
+
const coll = await getUserCollectionName(req.me);
|
|
27
26
|
if (collectionNames.includes(coll)) {
|
|
28
27
|
const collection = await MongoDatabase.createCollection(coll);
|
|
29
28
|
const indexes = await collection.indexes();
|
|
@@ -83,33 +82,11 @@ export const generateLimiter = rateLimit({
|
|
|
83
82
|
}
|
|
84
83
|
});
|
|
85
84
|
|
|
86
|
-
const freeSearchLimiter = rateLimit({
|
|
87
|
-
windowMs: 1000 * 3600,
|
|
88
|
-
limit: plans.free.requestLimitPerHour,
|
|
89
|
-
standardHeaders: true,
|
|
90
|
-
legacyHeaders: false,
|
|
91
|
-
});
|
|
92
|
-
const premiumSearchLimiter = rateLimit({
|
|
93
|
-
windowMs: 1000 * 3600,
|
|
94
|
-
limit: plans.premium.requestLimitPerHour,
|
|
95
|
-
standardHeaders: true,
|
|
96
|
-
legacyHeaders: false,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
export const myFreePremiumAnonymousLimiter = async function (req, res, next) {
|
|
100
|
-
const user = req.me;
|
|
101
|
-
if (user?.userPlan === "premium") {
|
|
102
|
-
return premiumSearchLimiter(req, res, next);
|
|
103
|
-
}
|
|
104
|
-
return freeSearchLimiter(req, res, next);
|
|
105
|
-
};
|
|
106
85
|
|
|
107
86
|
let logger,engine;
|
|
108
87
|
export async function onInit(defaultEngine) {
|
|
109
88
|
engine = defaultEngine;
|
|
110
89
|
logger = engine.getComponent(Logger);
|
|
111
|
-
|
|
112
|
-
|
|
113
90
|
}
|
|
114
91
|
|
|
115
92
|
export async function hasPermission(permissionNames, user) {
|
|
@@ -119,7 +96,7 @@ export async function hasPermission(permissionNames, user) {
|
|
|
119
96
|
try {
|
|
120
97
|
// Si on a une string on le transforme en tableau.
|
|
121
98
|
const permissionNamesArray = Array.isArray(permissionNames) ? permissionNames : [permissionNames];
|
|
122
|
-
const collection = getCollectionForUser(user);
|
|
99
|
+
const collection = await getCollectionForUser(user);
|
|
123
100
|
|
|
124
101
|
const job = [
|
|
125
102
|
{
|
|
@@ -131,39 +108,39 @@ export async function hasPermission(permissionNames, user) {
|
|
|
131
108
|
$match: {
|
|
132
109
|
$expr: {
|
|
133
110
|
$and: [
|
|
134
|
-
{ $in: ['$_id', '$$rolesIds'] }
|
|
135
|
-
]
|
|
136
|
-
}
|
|
137
|
-
}
|
|
111
|
+
{ $in: ['$_id', '$$rolesIds'] }
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
}
|
|
138
115
|
},
|
|
139
116
|
{
|
|
140
117
|
$lookup: {
|
|
141
118
|
from: 'datas',
|
|
142
119
|
let: { rolePermissions: {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
120
|
+
"$map": {
|
|
121
|
+
"input": "$permissions",
|
|
122
|
+
"in": { "$toObjectId": "$$this" }
|
|
123
|
+
}
|
|
124
|
+
} },
|
|
148
125
|
pipeline: [
|
|
149
126
|
{
|
|
150
127
|
$match: {
|
|
151
128
|
$expr: {
|
|
152
129
|
$and: [
|
|
153
|
-
{ $in: ['$_id', '$$rolePermissions'] }
|
|
154
|
-
]
|
|
155
|
-
}
|
|
156
|
-
}
|
|
130
|
+
{ $in: ['$_id', '$$rolePermissions'] }
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
157
134
|
},
|
|
158
|
-
{ $limit: 1 }
|
|
135
|
+
{ $limit: 1 }
|
|
159
136
|
],
|
|
160
|
-
as: 'permissions'
|
|
161
|
-
}
|
|
137
|
+
as: 'permissions'
|
|
138
|
+
}
|
|
162
139
|
},
|
|
163
|
-
{ $unwind: { path: '$permissions', preserveNullAndEmptyArrays: true } }
|
|
140
|
+
{ $unwind: { path: '$permissions', preserveNullAndEmptyArrays: true } }
|
|
164
141
|
],
|
|
165
|
-
as: 'roles'
|
|
166
|
-
}
|
|
142
|
+
as: 'roles'
|
|
143
|
+
}
|
|
167
144
|
},
|
|
168
145
|
{ $unwind: { path: '$roles', preserveNullAndEmptyArrays: true } },
|
|
169
146
|
{ $match: { 'roles.permissions.name': { $in: permissionNamesArray } } }, // Match if permissions.name in array
|
|
@@ -186,7 +163,7 @@ export async function hasPermission(permissionNames, user) {
|
|
|
186
163
|
*/
|
|
187
164
|
export async function calculateTotalUserStorageUsage(user) {
|
|
188
165
|
const userId = user._user || user.username;
|
|
189
|
-
const datasCollection = getCollectionForUser(user);
|
|
166
|
+
const datasCollection = await getCollectionForUser(user);
|
|
190
167
|
const filesCollection = getCollection("files");
|
|
191
168
|
|
|
192
169
|
// Pipeline pour calculer la taille des documents de données
|
package/src/modules/workflow.js
CHANGED
|
@@ -131,7 +131,7 @@ export async function scheduleWorkflowTriggers() {
|
|
|
131
131
|
// Trouver tous les workflows actifs avec une cronExpression définie
|
|
132
132
|
const workflowsToSchedule = await datasCollection.find({
|
|
133
133
|
_model: 'workflowTrigger',
|
|
134
|
-
cronExpression: { $exists: true, $ne: "" }
|
|
134
|
+
cronExpression: { $exists: true, $ne: "" }
|
|
135
135
|
// Ajoutez d'autres conditions si nécessaire (ex: active: true)
|
|
136
136
|
}).toArray();
|
|
137
137
|
|
|
@@ -270,7 +270,7 @@ async function handleWebhookAction(actionDef, contextData, user, dbCollection) {
|
|
|
270
270
|
// 4. Prepare Fetch Options
|
|
271
271
|
const fetchOptions = {
|
|
272
272
|
method: method.toUpperCase(),
|
|
273
|
-
headers: headersObject
|
|
273
|
+
headers: headersObject // Native fetch accepts an object directly
|
|
274
274
|
};
|
|
275
275
|
|
|
276
276
|
if (bodyObject !== null && ['POST', 'PUT', 'PATCH'].includes(fetchOptions.method)) {
|
|
@@ -649,32 +649,33 @@ export async function executeStepAction(actionDef, contextData, user, dbCollecti
|
|
|
649
649
|
try {
|
|
650
650
|
let result;
|
|
651
651
|
switch (actionDef.type) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
652
|
+
case 'Log':
|
|
653
|
+
logger.info(`[Workflow Log Action] Action: ${actionDef.name}. Contexte:`, contextData);
|
|
654
|
+
result = { success: true, message: 'Log action executed successfully.' }; // <--- CORRECTION
|
|
655
|
+
break;
|
|
656
|
+
case 'Webhook':
|
|
657
|
+
result = await handleWebhookAction(actionDef, contextData, user, dbCollection);
|
|
658
|
+
break;
|
|
659
|
+
case 'CreateData':
|
|
660
|
+
result = await handleCreateDataAction(actionDef, contextData, user, dbCollection);
|
|
661
|
+
break;
|
|
662
|
+
case 'UpdateData':
|
|
663
|
+
result = await handleUpdateDataAction(actionDef, contextData, user);
|
|
664
|
+
break;
|
|
665
|
+
case 'DeleteData':
|
|
666
|
+
result = await handleDeleteDataAction(actionDef, contextData, user, dbCollection);
|
|
667
|
+
break;
|
|
668
|
+
case 'GenerateAIContent':
|
|
669
|
+
result = await executeGenerateAIContentAction(actionDef, contextData, user);
|
|
670
|
+
break;
|
|
671
|
+
case 'SendEmail':
|
|
672
|
+
result = await handleSendEmailAction(actionDef, contextData, user);
|
|
673
|
+
break;
|
|
674
|
+
|
|
674
675
|
// ... autres cases à venir ...
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
676
|
+
default:
|
|
677
|
+
logger.error(`[executeStepAction] Unknown action type: ${actionDef.type}`);
|
|
678
|
+
return { success: false, message: `Unknown action type: ${actionDef.type}` };
|
|
678
679
|
}
|
|
679
680
|
return result;
|
|
680
681
|
} catch (error) {
|
|
@@ -749,7 +750,7 @@ async function resolvePathValue(pathString, initialContext, user) {
|
|
|
749
750
|
|
|
750
751
|
let currentModelName = initialContext._model;
|
|
751
752
|
let currentDocId = new ObjectId(initialContext._id);
|
|
752
|
-
const collection = getCollectionForUser(user);
|
|
753
|
+
const collection = await getCollectionForUser(user);
|
|
753
754
|
|
|
754
755
|
// Construire le pipeline d'agrégation
|
|
755
756
|
const pipeline = [
|
|
@@ -862,7 +863,7 @@ export async function substituteVariables(template, contextData, user) {
|
|
|
862
863
|
// --- À partir d'ici, nous savons que `template` est une chaîne de caractères ---
|
|
863
864
|
|
|
864
865
|
// 4. Construire le contexte complet pour la substitution
|
|
865
|
-
const dbCollection = getCollectionForUser(user);
|
|
866
|
+
const dbCollection = await getCollectionForUser(user);
|
|
866
867
|
const userEnvVars = await dbCollection.find({ _model: 'env', _user: user.username }).toArray();
|
|
867
868
|
const userEnv = userEnvVars.reduce((acc, v) => ({ ...acc, [v.name]: v.value }), {});
|
|
868
869
|
|
|
@@ -972,7 +973,7 @@ export async function triggerWorkflows(triggerData, user, eventType) {
|
|
|
972
973
|
console.log(`[Workflow Trigger] Event: ${eventType}, Model: ${targetModelName}${dataId ? `, Data ID: ${dataId}` : ''}, User: ${user.username}`);
|
|
973
974
|
|
|
974
975
|
try {
|
|
975
|
-
const dbCollection = getCollectionForUser(user); // Collection des données utilisateur
|
|
976
|
+
const dbCollection = await getCollectionForUser(user); // Collection des données utilisateur
|
|
976
977
|
|
|
977
978
|
// 1. Trouver les WorkflowTriggers pertinents
|
|
978
979
|
const workflowTriggers = await dbCollection.find({
|
|
@@ -1008,29 +1009,29 @@ export async function triggerWorkflows(triggerData, user, eventType) {
|
|
|
1008
1009
|
continue; // Passer au trigger suivant si le filtre est invalide
|
|
1009
1010
|
}
|
|
1010
1011
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
} catch (filterError) {
|
|
1031
|
-
console.error(`[Workflow Trigger] Erreur lors de la conversion ou de l'exécution du dataFilter pour le trigger ${trigger._id}:`, filterError);
|
|
1032
|
-
continue; // Ne pas créer en cas d'erreur de filtre
|
|
1012
|
+
try {
|
|
1013
|
+
const finalFilter = {
|
|
1014
|
+
'$and': [
|
|
1015
|
+
dataFilterCondition // Applique la condition du trigger
|
|
1016
|
+
]
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
console.debug(`[Workflow Trigger] Vérification dataFilter pour trigger ${trigger._id} avec filtre combiné:`, JSON.stringify(finalFilter));
|
|
1020
|
+
|
|
1021
|
+
// Exécuter la vérification dans la base de données
|
|
1022
|
+
// Utilisation de countDocuments pour une vérification rapide
|
|
1023
|
+
const matchCount = await searchData({ user, query: { model: targetModelName, filter: finalFilter, limit: 1 } });
|
|
1024
|
+
|
|
1025
|
+
if (!matchCount.count) {
|
|
1026
|
+
console.debug(`[Workflow Trigger] Trigger ${trigger._id}: dataFilter non satisfait par la donnée ${dataId}. WorkflowRun non créé.`);
|
|
1027
|
+
continue; // Passer au trigger suivant
|
|
1028
|
+
} else {
|
|
1029
|
+
console.debug(`[Workflow Trigger] Trigger ${trigger._id}: dataFilter satisfait par la donnée ${dataId}.`);
|
|
1033
1030
|
}
|
|
1031
|
+
} catch (filterError) {
|
|
1032
|
+
console.error(`[Workflow Trigger] Erreur lors de la conversion ou de l'exécution du dataFilter pour le trigger ${trigger._id}:`, filterError);
|
|
1033
|
+
continue; // Ne pas créer en cas d'erreur de filtre
|
|
1034
|
+
}
|
|
1034
1035
|
} // Fin de la vérification dataFilter
|
|
1035
1036
|
|
|
1036
1037
|
// 4. Si les filtres (eventType, dataFilter) sont passés, créer l'instance workflowRun
|
|
@@ -1087,9 +1088,9 @@ export async function triggerWorkflows(triggerData, user, eventType) {
|
|
|
1087
1088
|
}
|
|
1088
1089
|
|
|
1089
1090
|
return new Promise((resolve) => setTimeout(async () => {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1091
|
+
await trigger(triggerData, user, eventType);
|
|
1092
|
+
resolve();
|
|
1093
|
+
}, 0)
|
|
1093
1094
|
);
|
|
1094
1095
|
}
|
|
1095
1096
|
|
|
@@ -1105,7 +1106,7 @@ export async function triggerWorkflows(triggerData, user, eventType) {
|
|
|
1105
1106
|
// C:/Dev/hackersonline-engine/server/src/modules/workflow.js
|
|
1106
1107
|
|
|
1107
1108
|
export async function processWorkflowRun(workflowRunId, user) {
|
|
1108
|
-
const dbCollection = getCollectionForUser(user);
|
|
1109
|
+
const dbCollection = await getCollectionForUser(user);
|
|
1109
1110
|
const runId = typeof workflowRunId === 'string' ? new ObjectId(workflowRunId) : workflowRunId;
|
|
1110
1111
|
|
|
1111
1112
|
logger.info(`[processWorkflowRun] Starting processing for workflowRun ID: ${runId}`);
|
|
@@ -1290,7 +1291,7 @@ async function executeGenerateAIContentAction(action, context, user) {
|
|
|
1290
1291
|
|
|
1291
1292
|
const providers = {
|
|
1292
1293
|
"OpenAI" : "OPENAI_API_KEY",
|
|
1293
|
-
"Google": "GOOGLE_API_KEY"
|
|
1294
|
+
"Google": "GOOGLE_API_KEY"
|
|
1294
1295
|
}
|
|
1295
1296
|
const envKeyName = providers[aiProvider];
|
|
1296
1297
|
if( !envKeyName ) {
|
|
@@ -1298,7 +1299,7 @@ async function executeGenerateAIContentAction(action, context, user) {
|
|
|
1298
1299
|
}
|
|
1299
1300
|
|
|
1300
1301
|
// Cherche d'abord dans les variables d'environnement de l'utilisateur
|
|
1301
|
-
const envCollection = getCollectionForUser(user);
|
|
1302
|
+
const envCollection = await getCollectionForUser(user);
|
|
1302
1303
|
const userEnvVar = await envCollection.findOne({ _model: 'env', name: envKeyName, _user: user.username });
|
|
1303
1304
|
|
|
1304
1305
|
if (userEnvVar && userEnvVar.value) {
|
|
@@ -1319,14 +1320,14 @@ async function executeGenerateAIContentAction(action, context, user) {
|
|
|
1319
1320
|
let llm;
|
|
1320
1321
|
try {
|
|
1321
1322
|
switch (aiProvider) {
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1323
|
+
case 'OpenAI':
|
|
1324
|
+
llm = new ChatOpenAI({ apiKey, modelName: aiModel, temperature: 0.7 });
|
|
1325
|
+
break;
|
|
1326
|
+
case 'GoogleGemini':
|
|
1327
|
+
llm = new ChatGoogleGenerativeAI({ apiKey, modelName: aiModel, temperature: 0.7 });
|
|
1328
|
+
break;
|
|
1329
|
+
default:
|
|
1330
|
+
throw new Error(`Fournisseur IA non supporté : ${aiProvider}`);
|
|
1330
1331
|
}
|
|
1331
1332
|
} catch (initError) {
|
|
1332
1333
|
const message = `Échec de l'initialisation du client IA pour ${aiProvider}: ${initError.message}`;
|
|
@@ -1413,7 +1414,7 @@ async function handleSendEmailAction(action, triggerData, user) {
|
|
|
1413
1414
|
// 3. Préparer les données pour sendEmail
|
|
1414
1415
|
const emailData = {
|
|
1415
1416
|
title: rsubject,
|
|
1416
|
-
content: rbody
|
|
1417
|
+
content: rbody
|
|
1417
1418
|
};
|
|
1418
1419
|
|
|
1419
1420
|
await sendEmail(rto, emailData, smtpConfig, user.lang);
|
package/src/openai.jobs.js
CHANGED
|
@@ -121,10 +121,10 @@ export const openaiJobModel = async (lang, txt, history, existingModels = []) =>
|
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
role: "user",
|
|
124
|
-
content: typeof(txt) === 'string' ? txt.substring(0, 4096) : ''
|
|
124
|
+
content: typeof(txt) === 'string' ? txt.substring(0, 4096) : ''
|
|
125
125
|
},
|
|
126
126
|
...history
|
|
127
|
-
]
|
|
127
|
+
]
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
const aiResponse = completion.choices[0].message.content;
|
package/src/packs.js
CHANGED
|
@@ -135,21 +135,20 @@ export const getAllPacks = async () => {
|
|
|
135
135
|
}
|
|
136
136
|
],
|
|
137
137
|
"dashboard": [{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
}
|