data-primals-engine 1.0.5 → 1.0.7
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/package.json +12 -12
- package/src/constants.js +1 -79
- package/src/defaultModels.js +125 -13
- package/src/engine.js +14 -18
- package/src/i18n.js +4477 -16414
- package/src/modules/assistant.js +13 -6
- package/src/modules/bucket.js +2 -2
- package/src/modules/data.js +43 -38
- package/src/modules/user.js +1 -1
package/src/modules/assistant.js
CHANGED
|
@@ -20,7 +20,7 @@ export const assistantGlobalLimiter = rateLimit({
|
|
|
20
20
|
legacyHeaders: false, // Désactive les anciens en-têtes `X-RateLimit-*`
|
|
21
21
|
message: { success: false, message: "Trop de requêtes globales envoyées à l'assistant. Veuillez réessayer plus tard." },
|
|
22
22
|
skip: (req) => {
|
|
23
|
-
return !!req.
|
|
23
|
+
return !!req.fields?.confirmedAction;
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
|
|
@@ -63,7 +63,9 @@ Tu as accès aux outils suivants. Tu ne dois utiliser QUE ces outils.
|
|
|
63
63
|
|
|
64
64
|
La spécification, pour t'aider à construire les filtres, est la suivante :
|
|
65
65
|
utilise une chaine de caractère convertible en ObjectId (mongodb) lorsque le nom du champ est _id
|
|
66
|
-
utilise une chaine de caracteres lorsque le type de champ est :
|
|
66
|
+
utilise une chaine de caracteres lorsque le type de champ est : string, string_t , password, url, phone, email, richtext
|
|
67
|
+
utilise un $FILTER en retour si le type de champ est code et language='json' et conditionBuilder=true
|
|
68
|
+
utilise une chaine si c'est un type de champ code par défaut.
|
|
67
69
|
utilise une structure { "iso2langcode":"content..." } pour le champ multi-traductions richtext_t
|
|
68
70
|
utilise un booléen pour : boolean
|
|
69
71
|
utilise un nombre pour number
|
|
@@ -80,11 +82,18 @@ PROCESSUS DE RAISONNEMENT:
|
|
|
80
82
|
2. Tu analyses la question et choisis l'outil approprié.
|
|
81
83
|
3. Tu réponds IMMÉDIATEMENT avec l'objet JSON correspondant SANS COMMENTAIRE.
|
|
82
84
|
|
|
85
|
+
Chacune de tes réponses doit être une étape en soi, ou au plus près d'une étape.
|
|
86
|
+
|
|
83
87
|
CONTEXTE ACTUEL:
|
|
84
88
|
- L'utilisateur a accès aux modèles de données suivants et ne peut utiliser les filtres que sur les champs associés:
|
|
85
89
|
${modelDefs.map(m => ` - Modèle "${m.name}":\n Champs: ${JSON.stringify(m.fields.map(f => ({ name: f.name, type: f.type, hint: f.hint })), null, 2)}`).join('\n')}
|
|
86
90
|
- Le format de $DATA est { modelFieldName: "value", otherModelFieldName: { subObj : true } }
|
|
87
|
-
- Exemples de filtres
|
|
91
|
+
- Exemples de filtres $FILTER utilisables (ils sont compatibles MongoDB) :
|
|
92
|
+
Filtre utilisable : { $eq: ["$status", 500 ] }
|
|
93
|
+
Filtre incorrect : { "status": 500 }
|
|
94
|
+
==
|
|
95
|
+
|
|
96
|
+
Exemples de "params" :
|
|
88
97
|
Je voudrais les événements non terminés, qui ne sont pas des festivals ou des salons :
|
|
89
98
|
\`${cond1}\`
|
|
90
99
|
Donne moi les 5 nouvelles entreprises
|
|
@@ -93,8 +102,6 @@ Je veux les 10 dernières traductions ajoutées dans la langue française.
|
|
|
93
102
|
\`${cond3}\`
|
|
94
103
|
Je veux les commandes qui ont été faites par un admin ou un modérateur
|
|
95
104
|
\`${cond4}\`
|
|
96
|
-
Ton but est de créer un filtre au plus précis, et mets toujours un limit à 1 par défaut pour éviter de faire des actions en masse non désirées.
|
|
97
|
-
|
|
98
105
|
|
|
99
106
|
Règles ABSOLUES:
|
|
100
107
|
- UNE SEULE COMMANDE JSON PAR RÉPONSE
|
|
@@ -292,7 +299,7 @@ export async function onInit(engine) {
|
|
|
292
299
|
|
|
293
300
|
engine.post('/api/assistant/chat', [middlewareAuthenticator, userInitiator, assistantGlobalLimiter, generateLimiter], async (req, res) => {
|
|
294
301
|
// On récupère TOUTES les propriétés du body, y compris l'action confirmée
|
|
295
|
-
const {message, history, provider, context, confirmedAction} = req.
|
|
302
|
+
const {message, history, provider, context, confirmedAction} = req.fields;
|
|
296
303
|
|
|
297
304
|
// La validation ne s'applique que s'il n'y a pas d'action confirmée
|
|
298
305
|
if (!confirmedAction) {
|
package/src/modules/bucket.js
CHANGED
|
@@ -179,7 +179,7 @@ export async function onInit(defaultEngine) {
|
|
|
179
179
|
|
|
180
180
|
engine.post('/api/user/s3-config', [middlewareAuthenticator, userInitiator, myFreePremiumAnonymousLimiter], async (req, res) => {
|
|
181
181
|
const user = req.me;
|
|
182
|
-
const { bucketName, accessKeyId, secretAccessKey, region, pathPrefix } = req.
|
|
182
|
+
const { bucketName, accessKeyId, secretAccessKey, region, pathPrefix } = req.fields;
|
|
183
183
|
|
|
184
184
|
// Validation basique des entrées
|
|
185
185
|
if (!bucketName || !accessKeyId || !region) {
|
|
@@ -201,7 +201,7 @@ export async function onInit(defaultEngine) {
|
|
|
201
201
|
} else {
|
|
202
202
|
// Si la clé secrète n'est pas fournie, on ne la modifie pas.
|
|
203
203
|
// Si tu veux permettre de la supprimer, il faudrait une logique explicite.
|
|
204
|
-
// Pour l'instant, on ne touche pas à s3Config.secretAccessKey si req.
|
|
204
|
+
// Pour l'instant, on ne touche pas à s3Config.secretAccessKey si req.fields.secretAccessKey est vide.
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
const result = await engine.userProvider.updateUser(
|
package/src/modules/data.js
CHANGED
|
@@ -77,7 +77,7 @@ import {openaiJobModel} from "../openai.jobs.js";
|
|
|
77
77
|
import checkDiskSpace from "check-disk-space";
|
|
78
78
|
import { fileURLToPath } from 'url';
|
|
79
79
|
import { Worker } from 'worker_threads';
|
|
80
|
-
import {encryptFile, removeFile} from "./file.js";
|
|
80
|
+
import {addFile, encryptFile, removeFile} from "./file.js";
|
|
81
81
|
import {listS3Backups, uploadToS3} from "./bucket.js";
|
|
82
82
|
import {
|
|
83
83
|
calculateTotalUserStorageUsage, generateLimiter, hasPermission,
|
|
@@ -1232,7 +1232,7 @@ export async function onInit(defaultEngine) {
|
|
|
1232
1232
|
|
|
1233
1233
|
engine.post('/api/magnets', [middlewareAuthenticator, userInitiator], async (req, res) => {
|
|
1234
1234
|
const user = req.me;
|
|
1235
|
-
const { name, description, modelNames } = req.
|
|
1235
|
+
const { name, description, modelNames } = req.fields; // Noms des modèles à inclure
|
|
1236
1236
|
|
|
1237
1237
|
if (!name || !Array.isArray(modelNames) || modelNames.length === 0) {
|
|
1238
1238
|
return res.status(400).json({ error: 'Name and a list of model names are required.' });
|
|
@@ -1401,7 +1401,7 @@ export async function onInit(defaultEngine) {
|
|
|
1401
1401
|
|
|
1402
1402
|
engine.post('/api/data/import', [middlewareAuthenticator, userInitiator, myFreePremiumAnonymousLimiter, setTimeoutMiddleware(60000)], async (req, res) => {
|
|
1403
1403
|
// ... (vérifications de permissions existantes) ...
|
|
1404
|
-
const result = await importData(req.
|
|
1404
|
+
const result = await importData(req.fields, req.files, req.me);
|
|
1405
1405
|
if( result.success ){
|
|
1406
1406
|
res.status(202).json(result);
|
|
1407
1407
|
}else{
|
|
@@ -1412,7 +1412,7 @@ export async function onInit(defaultEngine) {
|
|
|
1412
1412
|
|
|
1413
1413
|
engine.post('/api/model/generate', [middlewareAuthenticator, userInitiator, assistantGlobalLimiter, generateLimiter, setTimeoutMiddleware(30000)], async (req, res) => {
|
|
1414
1414
|
// --- NOUVELLE LOGIQUE : Accepter le prompt ET un modèle existant ---
|
|
1415
|
-
const { prompt, history = [], existingModel } = req.
|
|
1415
|
+
const { prompt, history = [], existingModel } = req.fields;
|
|
1416
1416
|
const user = req.me;
|
|
1417
1417
|
const lang = req.query.lang || 'en';
|
|
1418
1418
|
|
|
@@ -1463,7 +1463,7 @@ export async function onInit(defaultEngine) {
|
|
|
1463
1463
|
return res.status(403).json({success: false, error: i18n.t('api.permission.editModel', 'Cannot edit models from the API')})
|
|
1464
1464
|
}
|
|
1465
1465
|
|
|
1466
|
-
const dataModel = req.
|
|
1466
|
+
const dataModel = req.fields;
|
|
1467
1467
|
try {
|
|
1468
1468
|
const collection = getCollectionForUser(req.me);
|
|
1469
1469
|
validateModelStructure(dataModel);
|
|
@@ -1480,13 +1480,13 @@ export async function onInit(defaultEngine) {
|
|
|
1480
1480
|
}
|
|
1481
1481
|
|
|
1482
1482
|
// renommage du modèle
|
|
1483
|
-
if (typeof (req.
|
|
1484
|
-
await collection.updateMany({ _model: el.name }, { $set: { _model: req.
|
|
1483
|
+
if (typeof (req.fields.name)==='string'&&el.name !== req.fields.name && req.fields.name ){
|
|
1484
|
+
await collection.updateMany({ _model: el.name }, { $set: { _model: req.fields.name }});
|
|
1485
1485
|
await modelsCollection.updateMany({ 'fields' : {
|
|
1486
1486
|
'$elemMatch' : { relation: el.name }
|
|
1487
1487
|
}}, {
|
|
1488
1488
|
$set : {
|
|
1489
|
-
'fields.$.relation' : req.
|
|
1489
|
+
'fields.$.relation' : req.fields.name
|
|
1490
1490
|
}
|
|
1491
1491
|
})
|
|
1492
1492
|
}
|
|
@@ -1526,7 +1526,7 @@ export async function onInit(defaultEngine) {
|
|
|
1526
1526
|
await collection.updateMany({ _model: el.name }, { $unset: unset });
|
|
1527
1527
|
|
|
1528
1528
|
// sauvegarde du modele
|
|
1529
|
-
const set = {...req.
|
|
1529
|
+
const set = {...req.fields};
|
|
1530
1530
|
delete set['_id'];
|
|
1531
1531
|
await modelsCollection.updateOne({_id: new ObjectId(req.params.id)}, {$set: set});
|
|
1532
1532
|
|
|
@@ -1579,8 +1579,9 @@ export async function onInit(defaultEngine) {
|
|
|
1579
1579
|
});
|
|
1580
1580
|
|
|
1581
1581
|
engine.post('/api/data', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger, myFreePremiumAnonymousLimiter, setTimeoutMiddleware(15000)], async (req, res) => {
|
|
1582
|
-
const
|
|
1583
|
-
const
|
|
1582
|
+
const body = req.files ? req.fields : req.fields;
|
|
1583
|
+
const modelName = body.model; // Les données à insérer/mettre à jour (assurez-vous de valider et nettoyer ces données côté client et serveur !)
|
|
1584
|
+
const data = body.data || (body._data && JSON.parse(body._data));
|
|
1584
1585
|
|
|
1585
1586
|
try {
|
|
1586
1587
|
const model = await getModel(modelName, req.me);
|
|
@@ -1594,10 +1595,10 @@ export async function onInit(defaultEngine) {
|
|
|
1594
1595
|
});
|
|
1595
1596
|
|
|
1596
1597
|
engine.post('/api/data/search', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger, myFreePremiumAnonymousLimiter, setTimeoutMiddleware(30000)], async (req, res) => {
|
|
1597
|
-
const { pack } = req.
|
|
1598
|
+
const { pack } = req.fields;
|
|
1598
1599
|
|
|
1599
1600
|
try {
|
|
1600
|
-
const {data, count} = await searchData({query: {...req.query, model: req.
|
|
1601
|
+
const {data, count} = await searchData({query: {...req.query, model: req.fields.model || req.query.model, filter: req.fields.filter, pack}, user: req.me });
|
|
1601
1602
|
|
|
1602
1603
|
if( req.query.attachment ) {
|
|
1603
1604
|
res.attachment(req.query.attachment);
|
|
@@ -1622,7 +1623,7 @@ export async function onInit(defaultEngine) {
|
|
|
1622
1623
|
|
|
1623
1624
|
engine.delete('/api/data/:ids', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger, setTimeoutMiddleware(15000)], async (req, res) => {
|
|
1624
1625
|
const ids = req.params.ids.split(',');
|
|
1625
|
-
const r = await deleteData(req.
|
|
1626
|
+
const r = await deleteData(req.fields.model, ids, {}, req.me);
|
|
1626
1627
|
if( r.error) {
|
|
1627
1628
|
return res.status(r.statusCode || 400).json(r);
|
|
1628
1629
|
}else{
|
|
@@ -1631,7 +1632,7 @@ export async function onInit(defaultEngine) {
|
|
|
1631
1632
|
});
|
|
1632
1633
|
|
|
1633
1634
|
engine.delete('/api/data', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger, setTimeoutMiddleware(15000)], async (req, res) => {
|
|
1634
|
-
const r = await deleteData(req.
|
|
1635
|
+
const r = await deleteData(req.fields.model, [], req.fields.filter, req.me);
|
|
1635
1636
|
if( r.error) {
|
|
1636
1637
|
return res.status(r.statusCode || 400).json(r);
|
|
1637
1638
|
}else{
|
|
@@ -1642,9 +1643,9 @@ export async function onInit(defaultEngine) {
|
|
|
1642
1643
|
// --- Export Endpoint ---
|
|
1643
1644
|
engine.post('/api/data/export', [middlewareAuthenticator, throttle, userInitiator, myFreePremiumAnonymousLimiter, setTimeoutMiddleware(60000)], async (req, res) => {
|
|
1644
1645
|
try {
|
|
1645
|
-
const results = await exportData({...req.
|
|
1646
|
+
const results = await exportData({...req.fields, depth:req.query.depth, lang: req.query.lang}, req.me);
|
|
1646
1647
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
1647
|
-
const filename = `export-${req.
|
|
1648
|
+
const filename = `export-${req.fields.models.join('-')}-${timestamp}.json`;
|
|
1648
1649
|
|
|
1649
1650
|
if (!results.success) {
|
|
1650
1651
|
res.status(400).json(results); // Renvoyer l'objet d'erreur complet
|
|
@@ -1669,10 +1670,10 @@ export async function onInit(defaultEngine) {
|
|
|
1669
1670
|
});
|
|
1670
1671
|
|
|
1671
1672
|
engine.patch('/api/data/:id?', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger], async (req, res) => {
|
|
1672
|
-
const filter = req.
|
|
1673
|
+
const filter = req.fields.filter;
|
|
1673
1674
|
const hash = req.params.id; // Récupérer l'identifiant de la ressource à modifier
|
|
1674
|
-
const data = req.
|
|
1675
|
-
const r = await patchData(req.
|
|
1675
|
+
const data = req.fields.data || (req.fields._data && JSON.parse(req.fields._data));
|
|
1676
|
+
const r = await patchData(req.fields.model, filter || hash, data, req.files, req.me);
|
|
1676
1677
|
if (r.error) {
|
|
1677
1678
|
res.status(400).json(r);
|
|
1678
1679
|
} else {
|
|
@@ -1682,10 +1683,10 @@ export async function onInit(defaultEngine) {
|
|
|
1682
1683
|
|
|
1683
1684
|
engine.put('/api/data/:id?', [throttle, middlewareAuthenticator, userInitiator, middlewareLogger], async (req, res) => {
|
|
1684
1685
|
try {
|
|
1685
|
-
const filter = req.
|
|
1686
|
+
const filter = req.fields.filter;
|
|
1686
1687
|
const hash = req.params.id; // Récupérer l'identifiant de la ressource à modifier
|
|
1687
|
-
const data = req.
|
|
1688
|
-
const r = await editData(req.
|
|
1688
|
+
const data = req.fields.data || (req.fields._data && JSON.parse(req.fields._data));
|
|
1689
|
+
const r = await editData(req.fields.model, filter || hash, data, req.files, req.me)
|
|
1689
1690
|
if (r.error)
|
|
1690
1691
|
res.status(400).json(r);
|
|
1691
1692
|
else
|
|
@@ -1741,7 +1742,7 @@ export async function onInit(defaultEngine) {
|
|
|
1741
1742
|
return res.status(403).json({success: false, error: i18n.t('api.permission.addModel')})
|
|
1742
1743
|
}
|
|
1743
1744
|
try {
|
|
1744
|
-
const modelData = req.
|
|
1745
|
+
const modelData = req.fields;
|
|
1745
1746
|
validateModelStructure(modelData);
|
|
1746
1747
|
|
|
1747
1748
|
|
|
@@ -1795,7 +1796,7 @@ export async function onInit(defaultEngine) {
|
|
|
1795
1796
|
return res.status(403).json({success: false, error: i18n.t('api.permission.importModels')})
|
|
1796
1797
|
}
|
|
1797
1798
|
try {
|
|
1798
|
-
const modelsToImport = await modelsCollection.find({name: { $in: req.
|
|
1799
|
+
const modelsToImport = await modelsCollection.find({name: { $in: req.fields.models }, _user: { $exists: false } }).toArray();
|
|
1799
1800
|
const ids = [];
|
|
1800
1801
|
|
|
1801
1802
|
const getPromise = () => {
|
|
@@ -1808,13 +1809,17 @@ export async function onInit(defaultEngine) {
|
|
|
1808
1809
|
return Promise.reject();
|
|
1809
1810
|
})));
|
|
1810
1811
|
}
|
|
1811
|
-
const install = !!req.
|
|
1812
|
+
const install = !!req.fields.install;
|
|
1812
1813
|
if( install && /^demo[0-9]{1,2}$/.test(req.me.username) ){
|
|
1813
1814
|
|
|
1814
1815
|
await datasCollection.deleteMany({ _user: req.me.username});
|
|
1815
1816
|
await modelsCollection.deleteMany({ _user: req.me.username});
|
|
1816
1817
|
const files = await filesCollection.find({ mainUser: req.me.username}).toArray();
|
|
1817
|
-
|
|
1818
|
+
try {
|
|
1819
|
+
files.forEach(file =>removeFile(file.guid, req.me));
|
|
1820
|
+
} catch (e) {
|
|
1821
|
+
|
|
1822
|
+
}
|
|
1818
1823
|
|
|
1819
1824
|
await cancelAlerts(req.me);
|
|
1820
1825
|
|
|
@@ -1888,7 +1893,7 @@ export async function onInit(defaultEngine) {
|
|
|
1888
1893
|
|
|
1889
1894
|
try {
|
|
1890
1895
|
const modelId = req.params.modelId;
|
|
1891
|
-
const { oldFieldName, newFieldName } = req.
|
|
1896
|
+
const { oldFieldName, newFieldName } = req.fields;
|
|
1892
1897
|
|
|
1893
1898
|
// Basic validation
|
|
1894
1899
|
if (!oldFieldName || !newFieldName) {
|
|
@@ -2097,7 +2102,7 @@ export async function onInit(defaultEngine) {
|
|
|
2097
2102
|
|
|
2098
2103
|
engine.post('/api/charts/aggregate', [throttle, middlewareAuthenticator, userInitiator, myFreePremiumAnonymousLimiter, setTimeoutMiddleware(15000)], async (req, res) => {
|
|
2099
2104
|
// --- Récupérer groupByLabelField ---
|
|
2100
|
-
const { model: modelName, type, xAxis, yAxis, groupBy, aggregationType, groupByLabelField, filter: chartFilter } = req.
|
|
2105
|
+
const { model: modelName, type, xAxis, yAxis, groupBy, aggregationType, groupByLabelField, filter: chartFilter } = req.fields;
|
|
2101
2106
|
|
|
2102
2107
|
// --- Validation (inchangée) ---
|
|
2103
2108
|
const isGroupingChart = ['pie', 'doughnut'].includes(type);
|
|
@@ -2321,7 +2326,7 @@ export async function onInit(defaultEngine) {
|
|
|
2321
2326
|
if( !/^demo[0-9]{1,2}$/.test(req.me.username) && isLocalUser(req.me) && !await hasPermission(["API_ADMIN", "API_CREATE_PACK"], req.me)){
|
|
2322
2327
|
return res.status(403).json({success: false, error: i18n.t('api.permission.createPack')})
|
|
2323
2328
|
}
|
|
2324
|
-
const { itemIds } = req.
|
|
2329
|
+
const { itemIds } = req.fields;
|
|
2325
2330
|
if (!Array.isArray(itemIds) || itemIds.length === 0 || !itemIds.every(isObjectId)) { // Assurez-vous que isObjectId est importé/défini
|
|
2326
2331
|
return res.status(400).json({ success: false, error: 'itemIds must be a non-empty array of valid ObjectIds.' });
|
|
2327
2332
|
}
|
|
@@ -2451,7 +2456,7 @@ export async function onInit(defaultEngine) {
|
|
|
2451
2456
|
});
|
|
2452
2457
|
|
|
2453
2458
|
engine.post('/api/data/addToPack', [throttle, middlewareAuthenticator, userInitiator,myFreePremiumAnonymousLimiter], async (req, res) => {
|
|
2454
|
-
const { packName, itemIds } = req.
|
|
2459
|
+
const { packName, itemIds } = req.fields;
|
|
2455
2460
|
const user = req.me;
|
|
2456
2461
|
|
|
2457
2462
|
if( !/^demo[0-9]{1,2}$/.test(req.me.username) && isLocalUser(req.me) && !await hasPermission(["API_ADMIN", "API_CREATE_PACK"], req.me)){
|
|
@@ -2521,7 +2526,7 @@ export async function onInit(defaultEngine) {
|
|
|
2521
2526
|
/*
|
|
2522
2527
|
engine.post('/api/packs/install', [throttle, middlewareAuthenticator, userInitiator, myFreePremiumAnonymousLimiter], async (req, res) => {
|
|
2523
2528
|
|
|
2524
|
-
const { pack } = req.
|
|
2529
|
+
const { pack } = req.fields;
|
|
2525
2530
|
const initialModelName = req.query.model; // The starting model
|
|
2526
2531
|
const user = req.me;
|
|
2527
2532
|
const collection = getCollectionForUser(user);
|
|
@@ -3386,12 +3391,12 @@ const internalEditOrPatchData = async (modelName, filter, data, files, user, isP
|
|
|
3386
3391
|
// Traitement des fichiers
|
|
3387
3392
|
const fileFields = model.fields.filter(f => f.type === 'file' || (f.type === 'array' && f.itemsType === 'file'));
|
|
3388
3393
|
for (const field of fileFields) {
|
|
3389
|
-
if (files?.[field.name]) {
|
|
3394
|
+
if (files?.[field.name+'[0]']) {
|
|
3390
3395
|
if (field.type === 'file') {
|
|
3391
|
-
updateData[field.name] = await addFile(files[field.name][0], user);
|
|
3396
|
+
updateData[field.name] = await addFile(files[field.name+'[0]'][0], user);
|
|
3392
3397
|
} else if (field.type === 'array' && field.itemsType === 'file') {
|
|
3393
3398
|
const currentFiles = existingDocs[0]?.[field.name] || [];
|
|
3394
|
-
const newFiles = await processFileArray(files[field.name], currentFiles, user);
|
|
3399
|
+
const newFiles = await processFileArray(files[field.name+'[0]'], currentFiles, user);
|
|
3395
3400
|
updateData[field.name] = newFiles;
|
|
3396
3401
|
}
|
|
3397
3402
|
}
|
|
@@ -3490,7 +3495,7 @@ const internalEditOrPatchData = async (modelName, filter, data, files, user, isP
|
|
|
3490
3495
|
// Fonctions helper
|
|
3491
3496
|
async function processFileArray(files, currentFiles, user) {
|
|
3492
3497
|
const newFiles = await Promise.allSettled(
|
|
3493
|
-
files.map(async (file, i) => {
|
|
3498
|
+
Object.keys(files).map(f=>files[f]).map(async (file, i) => {
|
|
3494
3499
|
const oldFile = currentFiles.find(f => f.name === file.name);
|
|
3495
3500
|
if (oldFile && !file.newFile) return oldFile;
|
|
3496
3501
|
if (file.guid) return file;
|
|
@@ -3500,7 +3505,7 @@ async function processFileArray(files, currentFiles, user) {
|
|
|
3500
3505
|
).then(results => results.map(r => r.value).filter(Boolean));
|
|
3501
3506
|
|
|
3502
3507
|
// Suppression des anciens fichiers non réutilisés
|
|
3503
|
-
await Promise.
|
|
3508
|
+
await Promise.allSettled(
|
|
3504
3509
|
currentFiles
|
|
3505
3510
|
.filter(f => !newFiles.some(nf => nf._id === f._id))
|
|
3506
3511
|
.map(f => removeFile(f, user))
|
|
@@ -5241,7 +5246,7 @@ async function logApiRequest(req, res, user, startTime, responseBody = null, err
|
|
|
5241
5246
|
// Champs optionnels
|
|
5242
5247
|
ip: req.clientIp.substring('::ffff:'.length) || req.clientIp, // Obtenir l'IP du client
|
|
5243
5248
|
//requestHeaders: JSON.stringify(req.headers).substring(0, maxStringLength), // Optionnel: Peut être volumineux
|
|
5244
|
-
requestBody: req.
|
|
5249
|
+
requestBody: req.fields,
|
|
5245
5250
|
responseBody: res.statusCode >= 400 && responseBody ? JSON.stringify(responseBody).substring(0, maxStringLength) : null, // Optionnel: Peut être volumineux
|
|
5246
5251
|
error: error ? String(error.message || error) : null // Message d'erreur si applicable
|
|
5247
5252
|
};
|