data-primals-engine 1.5.2 → 1.6.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 (70) hide show
  1. package/README.md +938 -915
  2. package/client/README.md +136 -136
  3. package/client/index.js +0 -1
  4. package/client/public/doc/API.postman_collection.json +213 -213
  5. package/client/public/react.svg +9 -9
  6. package/client/src/AddWidgetTypeModal.jsx +47 -47
  7. package/client/src/App.css +42 -42
  8. package/client/src/App.jsx +92 -150
  9. package/client/src/App.scss +6 -0
  10. package/client/src/AssistantChat.jsx +362 -363
  11. package/client/src/Button.jsx +12 -12
  12. package/client/src/Dashboard.jsx +480 -480
  13. package/client/src/DashboardHtmlViewItem.jsx +146 -146
  14. package/client/src/DashboardView.jsx +654 -654
  15. package/client/src/DataEditor.jsx +383 -383
  16. package/client/src/DataLayout.jsx +779 -808
  17. package/client/src/DataTable.jsx +782 -822
  18. package/client/src/DataTable.scss +186 -186
  19. package/client/src/GeolocationField.jsx +93 -93
  20. package/client/src/HistoryDialog.jsx +307 -307
  21. package/client/src/HistoryDialog.scss +319 -319
  22. package/client/src/HtmlViewBuilderModal.jsx +90 -90
  23. package/client/src/HtmlViewBuilderModal.scss +17 -17
  24. package/client/src/HtmlViewCard.jsx +43 -43
  25. package/client/src/ModelCreator.jsx +683 -686
  26. package/client/src/ModelCreator.scss +1 -1
  27. package/client/src/ModelCreatorField.jsx +950 -950
  28. package/client/src/ModelImporter.jsx +3 -0
  29. package/client/src/ModelList.jsx +280 -280
  30. package/client/src/Notification.jsx +136 -136
  31. package/client/src/PackGallery.jsx +391 -391
  32. package/client/src/PackGallery.scss +231 -231
  33. package/client/src/Pagination.jsx +143 -143
  34. package/client/src/RelationField.jsx +354 -354
  35. package/client/src/RelationSelectorWidget.jsx +172 -172
  36. package/client/src/RelationValue.jsx +2 -1
  37. package/client/src/contexts/CommandContext.jsx +260 -0
  38. package/client/src/contexts/ModelContext.jsx +4 -1
  39. package/client/src/contexts/UIContext.jsx +72 -72
  40. package/client/src/filter.js +263 -263
  41. package/client/src/index.css +90 -90
  42. package/package.json +6 -5
  43. package/perf/artillery-hooks.js +37 -37
  44. package/perf/setup.yml +25 -25
  45. package/src/constants.js +4 -0
  46. package/src/defaultModels.js +7 -0
  47. package/src/engine.js +335 -335
  48. package/src/events.js +232 -137
  49. package/src/filter.js +274 -274
  50. package/src/index.js +1 -0
  51. package/src/modules/assistant/assistant.js +225 -83
  52. package/src/modules/auth-google/index.js +50 -50
  53. package/src/modules/auth-microsoft/index.js +81 -81
  54. package/src/modules/data/data.core.js +118 -118
  55. package/src/modules/data/data.history.js +555 -555
  56. package/src/modules/data/data.operations.js +112 -9
  57. package/src/modules/data/data.relations.js +686 -686
  58. package/src/modules/data/data.routes.js +1879 -1879
  59. package/src/modules/data/data.validation.js +2 -2
  60. package/src/modules/file.js +247 -247
  61. package/src/modules/user.js +14 -9
  62. package/src/packs.js +2 -2
  63. package/src/providers.js +2 -2
  64. package/src/services/stripe.js +196 -196
  65. package/src/sso.js +193 -193
  66. package/test/data.history.integration.test.js +264 -264
  67. package/test/data.integration.test.js +1281 -1206
  68. package/test/events.test.js +108 -10
  69. package/test/model.integration.test.js +377 -377
  70. package/test/user.test.js +106 -1
package/src/sso.js CHANGED
@@ -1,194 +1,194 @@
1
- import passport from 'passport';
2
- import session from 'express-session';
3
- import {Behaviour, Logger} from './gameObject.js';
4
- import { cookiesSecret } from "./constants.js";
5
- import {UserProvider} from "./providers.js";
6
- import {getCollection} from "./modules/mongodb.js";
7
- import process from "process";
8
-
9
- /**
10
- * @class SSOUserProvider
11
- * Gère les utilisateurs provenant de fournisseurs d'identité externes (SSO).
12
- * Sa responsabilité principale est de trouver un utilisateur existant correspondant
13
- * au profil SSO ou d'en créer un nouveau si nécessaire (provisioning à la volée).
14
- */
15
- export class SSOUserProvider extends UserProvider {
16
-
17
- usersCollection;
18
-
19
- constructor(engine) {
20
- super(engine);
21
- // Idéalement, la collection d'utilisateurs devrait être centralisée.
22
- // Pour cet exemple, nous la récupérons directement.
23
- this.usersCollection = getCollection("users"); // Assurez-vous que cette collection existe
24
- }
25
-
26
- /**
27
- * Trouve un utilisateur par son ID. Nécessaire pour la désérialisation de Passport.
28
- * @param {string} id - L'ID de l'utilisateur.
29
- * @returns {Promise<object|null>}
30
- */
31
- async findUserById(id) {
32
- // Note: Assurez-vous que vos utilisateurs ont un champ `_id` stable.
33
- // Si vous utilisez le `username` comme identifiant principal, adaptez cette méthode.
34
- try {
35
- const { ObjectId } = await import('mongodb');
36
- return await this.usersCollection.findOne({ _id: new ObjectId(id) });
37
- } catch (e) {
38
- return null; // Gère le cas où l'ID n'est pas un ObjectId valide
39
- }
40
- }
41
-
42
- /**
43
- * La méthode clé pour l'intégration SSO.
44
- * Cherche un utilisateur basé sur le profil fourni par le fournisseur d'identité.
45
- * S'il n'existe pas, il le crée.
46
- * @param {object} profile - Le profil utilisateur de Passport (ex: de Google, SAML).
47
- * @returns {Promise<object>} L'utilisateur de votre système.
48
- */
49
- async findOrCreate(profile) {
50
- if (!profile.emails || !profile.emails[0] || !profile.emails[0].value) {
51
- throw new Error("Le profil du fournisseur d'identité ne contient pas d'email.");
52
- }
53
-
54
- const email = profile.emails[0].value;
55
-
56
- // 1. Chercher un utilisateur existant avec cet email.
57
- const existingUser = await this.usersCollection.findOne({ email: email });
58
-
59
- if (existingUser) {
60
- // TODO: Mettre à jour les informations de l'utilisateur si nécessaire (ex: nom, photo de profil)
61
- // await this.usersCollection.updateOne({ _id: existingUser._id }, { $set: { lastLogin: new Date() } });
62
- return existingUser;
63
- }
64
-
65
- // 2. Si aucun utilisateur n'est trouvé, en créer un nouveau.
66
- const newUser = {
67
- username: email, // Utiliser l'email comme nom d'utilisateur par défaut
68
- email: email,
69
- name: profile.displayName || email,
70
- provider: profile.provider, // ex: 'google', 'saml'
71
- providerId: profile.id,
72
- userPlan: 'free', // Assigner un plan par défaut
73
- createdAt: new Date()
74
- };
75
-
76
- const result = await this.usersCollection.insertOne(newUser);
77
- return await this.findUserById(result.insertedId);
78
- }
79
-
80
- // Les autres méthodes comme validatePassword ne sont pas pertinentes pour le SSO.
81
- // On peut les laisser vides ou les faire lever une erreur.
82
- async validatePassword(user, password) { return false; }
83
- async findUserByUsername(username) { return await this.usersCollection.findOne({ username }); }
84
- async initiateUser(req) { /* Géré par Passport */ }
85
- }
86
-
87
- /**
88
- * @class Sso
89
- * @extends Behaviour
90
- * Un composant réutilisable qui encapsule la logique de Passport.js pour l'authentification.
91
- * Il gère la session, la sérialisation, et permet à d'autres modules d'enregistrer
92
- * dynamiquement des stratégies d'authentification (Google, SAML, etc.).
93
- */
94
- export class Sso extends Behaviour {
95
- #ssoUserProvider = null;
96
- #logger = null;
97
-
98
- constructor(gameObject) {
99
- super(gameObject);
100
- this.strategies = new Map();
101
- }
102
-
103
- /**
104
- * Initialise le composant avec les middlewares et la configuration de base de Passport.
105
- * @param {object} options
106
- * @param {UserProvider} options.ssoUserProvider - Le provider pour trouver ou créer des utilisateurs SSO.
107
- */
108
- initialize({ ssoUserProvider }) {
109
- if (!ssoUserProvider) {
110
- throw new Error("PassportAuth component requires an ssoUserProvider to be initialized.");
111
- }
112
- this.#ssoUserProvider = ssoUserProvider;
113
- this.#logger = this.gameObject.getComponent(Logger); // Assumant que Logger est un composant
114
-
115
- const app = this.gameObject; // this.gameObject est l'instance de l'engine (Express app)
116
-
117
- // 1. Configurer la session Express (prérequis pour Passport)
118
- app.use(session({
119
- secret: process.env.COOKIES_SECRET || cookiesSecret,
120
- resave: false,
121
- saveUninitialized: false,
122
- cookie: { secure: process.env.NODE_ENV === 'production', httpOnly: true, sameSite: 'lax' }
123
- }));
124
-
125
- // 2. Initialiser Passport
126
- app.use(passport.initialize());
127
- app.use(passport.session());
128
-
129
- // 3. Configurer la sérialisation/désérialisation
130
- passport.serializeUser((user, done) => {
131
- done(null, user._id);
132
- });
133
-
134
- passport.deserializeUser(async (id, done) => {
135
- try {
136
- const user = await this.#ssoUserProvider.findUserById(id);
137
- done(null, user);
138
- } catch (err) {
139
- done(err);
140
- }
141
- });
142
-
143
- this.#logger.info("PassportAuth component initialized successfully.");
144
- }
145
-
146
- /**
147
- * Permet à d'autres modules d'enregistrer une nouvelle stratégie d'authentification.
148
- * @param {string} name - Le nom de la stratégie (ex: 'google', 'saml').
149
- * @param {object} strategy - L'instance de la stratégie Passport.
150
- * @param {object} routes - Les chemins pour l'authentification.
151
- * @param {string} routes.authPath - Le chemin pour initier l'authentification (ex: '/api/auth/google').
152
- * @param {string} routes.callbackPath - Le chemin de callback (ex: '/api/auth/google/callback').
153
- * @param {object} options - Options d'authentification pour Passport (ex: { scope: ['profile', 'email'] }).
154
- */
155
- addStrategy(name, strategy, routes, options = {}) {
156
- if (this.strategies.has(name)) {
157
- this.#logger.warn(`Passport strategy '${name}' is already registered. Overwriting.`);
158
- }
159
-
160
- // Enregistrer la stratégie auprès de Passport
161
- passport.use(strategy);
162
-
163
- const app = this.gameObject;
164
-
165
- // Créer la route d'initiation
166
- app.get(routes.authPath, passport.authenticate(name, options));
167
-
168
- // Créer la route de callback
169
- app.get(
170
- routes.callbackPath,
171
- passport.authenticate(name, { failureRedirect: '/login', failureMessage: true }),
172
- (req, res) => {
173
- // Redirection après une authentification réussie
174
- res.redirect(req.session.returnTo || '/dashboard');
175
- delete req.session.returnTo;
176
- }
177
- );
178
-
179
- this.strategies.set(name, { strategy, routes, options });
180
- this.#logger.info(`Passport strategy '${name}' registered with routes: ${routes.authPath}, ${routes.callbackPath}`);
181
- }
182
-
183
- addLogoutRoute(path = '/api/auth/logout') {
184
- this.gameObject.get(path, (req, res, next) => {
185
- req.logout((err) => {
186
- if (err) { return next(err); }
187
- req.session.destroy(() => {
188
- res.redirect('/');
189
- });
190
- });
191
- });
192
- this.#logger.info(`Logout route registered at '${path}'.`);
193
- }
1
+ import passport from 'passport';
2
+ import session from 'express-session';
3
+ import {Behaviour, Logger} from './gameObject.js';
4
+ import { cookiesSecret } from "./constants.js";
5
+ import {UserProvider} from "./providers.js";
6
+ import {getCollection} from "./modules/mongodb.js";
7
+ import process from "process";
8
+
9
+ /**
10
+ * @class SSOUserProvider
11
+ * Gère les utilisateurs provenant de fournisseurs d'identité externes (SSO).
12
+ * Sa responsabilité principale est de trouver un utilisateur existant correspondant
13
+ * au profil SSO ou d'en créer un nouveau si nécessaire (provisioning à la volée).
14
+ */
15
+ export class SSOUserProvider extends UserProvider {
16
+
17
+ usersCollection;
18
+
19
+ constructor(engine) {
20
+ super(engine);
21
+ // Idéalement, la collection d'utilisateurs devrait être centralisée.
22
+ // Pour cet exemple, nous la récupérons directement.
23
+ this.usersCollection = getCollection("users"); // Assurez-vous que cette collection existe
24
+ }
25
+
26
+ /**
27
+ * Trouve un utilisateur par son ID. Nécessaire pour la désérialisation de Passport.
28
+ * @param {string} id - L'ID de l'utilisateur.
29
+ * @returns {Promise<object|null>}
30
+ */
31
+ async findUserById(id) {
32
+ // Note: Assurez-vous que vos utilisateurs ont un champ `_id` stable.
33
+ // Si vous utilisez le `username` comme identifiant principal, adaptez cette méthode.
34
+ try {
35
+ const { ObjectId } = await import('mongodb');
36
+ return await this.usersCollection.findOne({ _id: new ObjectId(id) });
37
+ } catch (e) {
38
+ return null; // Gère le cas où l'ID n'est pas un ObjectId valide
39
+ }
40
+ }
41
+
42
+ /**
43
+ * La méthode clé pour l'intégration SSO.
44
+ * Cherche un utilisateur basé sur le profil fourni par le fournisseur d'identité.
45
+ * S'il n'existe pas, il le crée.
46
+ * @param {object} profile - Le profil utilisateur de Passport (ex: de Google, SAML).
47
+ * @returns {Promise<object>} L'utilisateur de votre système.
48
+ */
49
+ async findOrCreate(profile) {
50
+ if (!profile.emails || !profile.emails[0] || !profile.emails[0].value) {
51
+ throw new Error("Le profil du fournisseur d'identité ne contient pas d'email.");
52
+ }
53
+
54
+ const email = profile.emails[0].value;
55
+
56
+ // 1. Chercher un utilisateur existant avec cet email.
57
+ const existingUser = await this.usersCollection.findOne({ email: email });
58
+
59
+ if (existingUser) {
60
+ // TODO: Mettre à jour les informations de l'utilisateur si nécessaire (ex: nom, photo de profil)
61
+ // await this.usersCollection.updateOne({ _id: existingUser._id }, { $set: { lastLogin: new Date() } });
62
+ return existingUser;
63
+ }
64
+
65
+ // 2. Si aucun utilisateur n'est trouvé, en créer un nouveau.
66
+ const newUser = {
67
+ username: email, // Utiliser l'email comme nom d'utilisateur par défaut
68
+ email: email,
69
+ name: profile.displayName || email,
70
+ provider: profile.provider, // ex: 'google', 'saml'
71
+ providerId: profile.id,
72
+ userPlan: 'free', // Assigner un plan par défaut
73
+ createdAt: new Date()
74
+ };
75
+
76
+ const result = await this.usersCollection.insertOne(newUser);
77
+ return await this.findUserById(result.insertedId);
78
+ }
79
+
80
+ // Les autres méthodes comme validatePassword ne sont pas pertinentes pour le SSO.
81
+ // On peut les laisser vides ou les faire lever une erreur.
82
+ async validatePassword(user, password) { return false; }
83
+ async findUserByUsername(username) { return await this.usersCollection.findOne({ username }); }
84
+ async initiateUser(req) { /* Géré par Passport */ }
85
+ }
86
+
87
+ /**
88
+ * @class Sso
89
+ * @extends Behaviour
90
+ * Un composant réutilisable qui encapsule la logique de Passport.js pour l'authentification.
91
+ * Il gère la session, la sérialisation, et permet à d'autres modules d'enregistrer
92
+ * dynamiquement des stratégies d'authentification (Google, SAML, etc.).
93
+ */
94
+ export class Sso extends Behaviour {
95
+ #ssoUserProvider = null;
96
+ #logger = null;
97
+
98
+ constructor(gameObject) {
99
+ super(gameObject);
100
+ this.strategies = new Map();
101
+ }
102
+
103
+ /**
104
+ * Initialise le composant avec les middlewares et la configuration de base de Passport.
105
+ * @param {object} options
106
+ * @param {UserProvider} options.ssoUserProvider - Le provider pour trouver ou créer des utilisateurs SSO.
107
+ */
108
+ initialize({ ssoUserProvider }) {
109
+ if (!ssoUserProvider) {
110
+ throw new Error("PassportAuth component requires an ssoUserProvider to be initialized.");
111
+ }
112
+ this.#ssoUserProvider = ssoUserProvider;
113
+ this.#logger = this.gameObject.getComponent(Logger); // Assumant que Logger est un composant
114
+
115
+ const app = this.gameObject; // this.gameObject est l'instance de l'engine (Express app)
116
+
117
+ // 1. Configurer la session Express (prérequis pour Passport)
118
+ app.use(session({
119
+ secret: process.env.COOKIES_SECRET || cookiesSecret,
120
+ resave: false,
121
+ saveUninitialized: false,
122
+ cookie: { secure: process.env.NODE_ENV === 'production', httpOnly: true, sameSite: 'lax' }
123
+ }));
124
+
125
+ // 2. Initialiser Passport
126
+ app.use(passport.initialize());
127
+ app.use(passport.session());
128
+
129
+ // 3. Configurer la sérialisation/désérialisation
130
+ passport.serializeUser((user, done) => {
131
+ done(null, user._id);
132
+ });
133
+
134
+ passport.deserializeUser(async (id, done) => {
135
+ try {
136
+ const user = await this.#ssoUserProvider.findUserById(id);
137
+ done(null, user);
138
+ } catch (err) {
139
+ done(err);
140
+ }
141
+ });
142
+
143
+ this.#logger.info("PassportAuth component initialized successfully.");
144
+ }
145
+
146
+ /**
147
+ * Permet à d'autres modules d'enregistrer une nouvelle stratégie d'authentification.
148
+ * @param {string} name - Le nom de la stratégie (ex: 'google', 'saml').
149
+ * @param {object} strategy - L'instance de la stratégie Passport.
150
+ * @param {object} routes - Les chemins pour l'authentification.
151
+ * @param {string} routes.authPath - Le chemin pour initier l'authentification (ex: '/api/auth/google').
152
+ * @param {string} routes.callbackPath - Le chemin de callback (ex: '/api/auth/google/callback').
153
+ * @param {object} options - Options d'authentification pour Passport (ex: { scope: ['profile', 'email'] }).
154
+ */
155
+ addStrategy(name, strategy, routes, options = {}) {
156
+ if (this.strategies.has(name)) {
157
+ this.#logger.warn(`Passport strategy '${name}' is already registered. Overwriting.`);
158
+ }
159
+
160
+ // Enregistrer la stratégie auprès de Passport
161
+ passport.use(strategy);
162
+
163
+ const app = this.gameObject;
164
+
165
+ // Créer la route d'initiation
166
+ app.get(routes.authPath, passport.authenticate(name, options));
167
+
168
+ // Créer la route de callback
169
+ app.get(
170
+ routes.callbackPath,
171
+ passport.authenticate(name, { failureRedirect: '/login', failureMessage: true }),
172
+ (req, res) => {
173
+ // Redirection après une authentification réussie
174
+ res.redirect(req.session.returnTo || '/dashboard');
175
+ delete req.session.returnTo;
176
+ }
177
+ );
178
+
179
+ this.strategies.set(name, { strategy, routes, options });
180
+ this.#logger.info(`Passport strategy '${name}' registered with routes: ${routes.authPath}, ${routes.callbackPath}`);
181
+ }
182
+
183
+ addLogoutRoute(path = '/api/auth/logout') {
184
+ this.gameObject.get(path, (req, res, next) => {
185
+ req.logout((err) => {
186
+ if (err) { return next(err); }
187
+ req.session.destroy(() => {
188
+ res.redirect('/');
189
+ });
190
+ });
191
+ });
192
+ this.#logger.info(`Logout route registered at '${path}'.`);
193
+ }
194
194
  }