data-primals-engine 1.6.3 → 1.7.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.
Files changed (55) hide show
  1. package/README.md +52 -900
  2. package/client/index.js +3 -0
  3. package/client/package-lock.json +7563 -8811
  4. package/client/package.json +11 -1
  5. package/client/src/App.scss +29 -0
  6. package/client/src/AssistantChat.jsx +369 -362
  7. package/client/src/DataEditor.jsx +383 -383
  8. package/client/src/DataLayout.jsx +54 -20
  9. package/client/src/ModelList.jsx +280 -280
  10. package/client/src/ViewSwitcher.scss +0 -31
  11. package/client/src/_variables.scss +3 -0
  12. package/client/src/constants.js +81 -100
  13. package/client/src/contexts/CommandContext.jsx +274 -259
  14. package/client/vite.config.js +30 -30
  15. package/doc/AI-assistance.md +93 -0
  16. package/doc/Advanced-workflows.md +90 -0
  17. package/doc/Event-system.md +79 -0
  18. package/doc/Packs-gallery.md +73 -0
  19. package/doc/automation-workflows.md +102 -0
  20. package/doc/core-concepts.md +33 -0
  21. package/doc/custom-api-endpoints.md +40 -0
  22. package/doc/dashboards-kpis-charts.md +49 -0
  23. package/doc/data-management.md +120 -0
  24. package/doc/data-models.md +75 -0
  25. package/doc/index.md +14 -0
  26. package/doc/roles-permissions.md +43 -0
  27. package/doc/users.md +30 -0
  28. package/package.json +20 -10
  29. package/src/client.js +6 -4
  30. package/src/constants.js +1 -1
  31. package/src/core.js +31 -12
  32. package/src/defaultModels.js +1 -1
  33. package/src/engine.js +342 -335
  34. package/src/filter.js +72 -173
  35. package/src/migrate.js +1 -1
  36. package/src/modules/assistant/assistant.js +30 -20
  37. package/src/modules/data/data.backup.js +4 -4
  38. package/src/modules/data/data.js +8 -7
  39. package/src/modules/data/data.operations.js +186 -133
  40. package/src/modules/data/data.relations.js +3 -2
  41. package/src/modules/data/data.scheduling.js +1 -1
  42. package/src/modules/mongodb.js +17 -8
  43. package/src/modules/swagger.js +25 -5
  44. package/src/modules/user.js +108 -79
  45. package/src/modules/workflow.js +138 -3
  46. package/src/packs.js +5697 -5697
  47. package/src/profiles.js +19 -0
  48. package/swagger-en.yml +3391 -1550
  49. package/swagger-fr.yml +3385 -2896
  50. package/test/assistant.test.js +2 -2
  51. package/test/core.test.js +341 -0
  52. package/test/data.backup.integration.test.js +3 -1
  53. package/test/data.history.integration.test.js +0 -1
  54. package/test/data.integration.test.js +137 -2
  55. package/test/user.test.js +33 -29
package/test/user.test.js CHANGED
@@ -16,34 +16,39 @@ describe('User Permission System with Filters', () => {
16
16
  let permNoFilter, permWithSimpleFilter, permWithUserFilter, permWithReqFilter, permOrderEditForManager;
17
17
  let roleWithPerms;
18
18
 
19
+ // Le parent qui possède les définitions de rôles et permissions
20
+ const parentUser = { username: generateUniqueName('perm_parent_user') };
21
+
19
22
  beforeAll(async () => {
20
23
  Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow", "user", "assistant"]);
21
24
  engine = await initEngine();
22
25
  logger = engine.getComponent(Logger);
23
26
  await onInit(engine);
27
+ // La collection est celle du parent, car c'est lui qui stocke les définitions
28
+ collection = await getCollectionForUser(parentUser);
24
29
  });
25
30
 
26
31
  beforeEach(async () => {
27
32
  // Utiliser un utilisateur unique pour l'isolation des tests
28
33
  const username = generateUniqueName('perm_test_user');
29
- testUser = { _id: new ObjectId(), username: username, _user: username, roles: [], _model: 'user' };
30
- testUserWithRole = { _id: new ObjectId(), username: username, _user: username, roles: [], _model: 'user' }; // roles sera ajouté après la création du rôle
34
+ // L'utilisateur de test est un "enfant" de parentUser
35
+ testUser = { _id: new ObjectId(), username: username, _user: parentUser.username, roles: [], _model: 'user' };
36
+ testUserWithRole = { _id: new ObjectId(), username: username, _user: parentUser.username, roles: [], _model: 'user' };
31
37
  systemUser = { roles: ['admin', 'product.view'] };
32
38
 
33
- collection = await getCollectionForUser(testUser);
34
- await collection.deleteMany({ _user: username });
39
+ await collection.deleteMany({ _user: parentUser.username });
35
40
 
36
41
  // --- Création des données de test ---
37
42
  // Créer les modèles nécessaires pour les permissions et les rôles
38
- await createModel({ name: 'permission', _user: username, fields: [{ name: 'name', type: 'string' }, { name: 'filter', type: 'code' }] });
39
- await createModel({ name: 'role', _user: username, fields: [{ name: 'name', type: 'string' }, { name: 'permissions', type: 'relation', relation: 'permission', multiple: true }] });
40
- await createModel({ name: 'userPermission', _user: username, fields: [{ name: 'user', type: 'relation', relation: 'user' }, { name: 'permission', type: 'relation', relation: 'permission' }, { name: 'isGranted', type: 'boolean' }, { name: 'filter', type: 'code' }] });
43
+ await createModel({ name: 'permission', description: '', _user: parentUser.username, fields: [{ name: 'name', type: 'string' }, { name: 'filter', type: 'code' }] });
44
+ await createModel({ name: 'role', description: '', _user: parentUser.username, fields: [{ name: 'name', type: 'string' }, { name: 'permissions', type: 'relation', relation: 'permission', multiple: true }] });
45
+ await createModel({ name: 'userPermission', description: '', _user: parentUser.username, fields: [{ name: 'user', type: 'relation', relation: 'user' }, { name: 'permission', type: 'relation', relation: 'permission' }, { name: 'isGranted', type: 'boolean' }, { name: 'filter', type: 'code',language:'json' }] });
41
46
 
42
47
  const permResult = await collection.insertMany([
43
- { _model: 'permission', name: 'product.view', _user: username },
44
- { _model: 'permission', name: 'order.edit', filter: { status: 'pending' }, _user: username },
45
- { _model: 'permission', name: 'document.edit', filter: { createdBy: '{user._id}' }, _user: username },
46
- { _model: 'permission', name: 'login.attempt', filter: { "ip": "{req.ip}" }, _user: username }
48
+ { _model: 'permission', name: 'product.view', _user: parentUser.username },
49
+ { _model: 'permission', name: 'order.edit', filter: { status: 'pending' }, _user: parentUser.username },
50
+ { _model: 'permission', name: 'document.edit', filter: { createdBy: '{user._id}' }, _user: parentUser.username },
51
+ { _model: 'permission', name: 'login.attempt', filter: { "ip": "{req.ip}" }, _user: parentUser.username }
47
52
  ]);
48
53
  permNoFilter = permResult.insertedIds[0];
49
54
  permWithSimpleFilter = permResult.insertedIds[1];
@@ -54,7 +59,7 @@ describe('User Permission System with Filters', () => {
54
59
  _model: 'role',
55
60
  name: 'Editor',
56
61
  permissions: [permNoFilter.toString(), permWithSimpleFilter.toString()],
57
- _user: username
62
+ _user: parentUser.username
58
63
  });
59
64
  roleWithPerms = roleResult.insertedId;
60
65
 
@@ -65,9 +70,9 @@ describe('User Permission System with Filters', () => {
65
70
  afterEach(async () => {
66
71
  // Nettoyer les données créées
67
72
  if (collection) {
68
- await collection.deleteMany({ _user: testUser.username });
73
+ await collection.deleteMany({ _user: parentUser.username });
69
74
  }
70
- await deleteModels({ _user: testUser.username });
75
+ await deleteModels({ _user: parentUser.username });
71
76
  });
72
77
 
73
78
  it('should return true for a permission without filter granted by a role', async () => {
@@ -91,7 +96,7 @@ describe('User Permission System with Filters', () => {
91
96
  user: testUser._id.toString(),
92
97
  permission: permWithUserFilter.toString(),
93
98
  isGranted: true,
94
- _user: testUser.username
99
+ _user: parentUser.username
95
100
  });
96
101
 
97
102
  const result = await hasPermission('document.edit', testUser);
@@ -104,7 +109,7 @@ describe('User Permission System with Filters', () => {
104
109
  user: testUserWithRole._id.toString(),
105
110
  permission: permWithUserFilter.toString(),
106
111
  isGranted: true,
107
- _user: testUser.username
112
+ _user: parentUser.username
108
113
  });
109
114
 
110
115
  const result = await hasPermission('document.edit', testUserWithRole);
@@ -117,7 +122,7 @@ describe('User Permission System with Filters', () => {
117
122
  user: testUser._id.toString(),
118
123
  permission: permWithReqFilter.toString(),
119
124
  isGranted: true,
120
- _user: testUser.username
125
+ _user: parentUser.username
121
126
  });
122
127
 
123
128
  const mockReq = {
@@ -134,14 +139,14 @@ describe('User Permission System with Filters', () => {
134
139
  it('should revoke a permission from a role via userPermission exception', async () => {
135
140
  let result = await hasPermission('order.edit', testUserWithRole);
136
141
  expect(result).toEqual({ status: 'pending' });
137
-
138
- await collection.insertOne({
139
- _model: 'userPermission',
142
+
143
+ // Utiliser insertData pour déclencher l'invalidation du cache
144
+ await insertData('userPermission', {
140
145
  user: testUserWithRole._id.toString(),
141
146
  permission: permWithSimpleFilter.toString(),
142
147
  isGranted: false,
143
- _user: testUser.username
144
- });
148
+ }, {}, parentUser, true, true, false // le dernier false pour bypasser la vérification de permission pour le test
149
+ );
145
150
 
146
151
  result = await hasPermission('order.edit', testUserWithRole);
147
152
  expect(result).toBe(false);
@@ -152,7 +157,7 @@ describe('User Permission System with Filters', () => {
152
157
  _model: 'permission',
153
158
  name: 'order.edit',
154
159
  filter: { manager_id: '{user._id}' },
155
- _user: testUser.username
160
+ _user: parentUser.username
156
161
  });
157
162
  permOrderEditForManager = permResult.insertedId;
158
163
 
@@ -161,7 +166,7 @@ describe('User Permission System with Filters', () => {
161
166
  user: testUserWithRole._id.toString(),
162
167
  permission: permOrderEditForManager.toString(),
163
168
  isGranted: true,
164
- _user: testUser.username
169
+ _user: parentUser.username
165
170
  });
166
171
 
167
172
  const result = await hasPermission('order.edit', testUserWithRole);
@@ -175,14 +180,13 @@ describe('User Permission System with Filters', () => {
175
180
  expect(result).toEqual({ status: 'pending' });
176
181
 
177
182
  // On ajoute une exception qui accorde la même permission mais avec un filtre différent
178
- await collection.insertOne({
179
- _model: 'userPermission',
183
+ // Utiliser insertData pour s'assurer que le cache est invalidé
184
+ await insertData('userPermission', {
180
185
  user: testUserWithRole._id.toString(),
181
186
  permission: permWithSimpleFilter.toString(), // La permission 'order.edit'
182
187
  isGranted: true,
183
188
  filter: { "assignedTo": "{user._id}" }, // Le nouveau filtre
184
- _user: testUser.username
185
- });
189
+ }, {}, parentUser, true, true, false);
186
190
 
187
191
  // La fonction doit maintenant retourner le filtre de l'exception
188
192
  result = await hasPermission('order.edit', testUserWithRole);
@@ -198,7 +202,7 @@ describe('User Permission System with Filters', () => {
198
202
  permission: permWithUserFilter.toString(), // La permission 'document.edit'
199
203
  isGranted: true,
200
204
  // Pas de champ 'filter' ici
201
- _user: testUser.username
205
+ _user: parentUser.username
202
206
  });
203
207
 
204
208
  // La fonction doit retourner le filtre de la permission de base.