@nkhang1902/strapi-plugin-export-import-clsx 1.1.1 → 1.1.13
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.
|
@@ -175,8 +175,9 @@ const ExportImportButtons = (props) => {
|
|
|
175
175
|
formData.append("file", file);
|
|
176
176
|
formData.append("contentType", contentType);
|
|
177
177
|
|
|
178
|
+
const eventFilter = getEventFilter();
|
|
178
179
|
try {
|
|
179
|
-
const response = await fetch(
|
|
180
|
+
const response = await fetch(`/export-import-clsx/import?eventId=${eventFilter.eventId}`, {
|
|
180
181
|
method: "POST",
|
|
181
182
|
body: formData,
|
|
182
183
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nkhang1902/strapi-plugin-export-import-clsx",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "A powerful Strapi plugin for exporting and importing data with Excel support and advanced filtering",
|
|
5
5
|
"main": "./strapi-server.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,7 +14,9 @@ module.exports = ({ strapi }) => ({
|
|
|
14
14
|
.plugin("export-import-clsx")
|
|
15
15
|
.service("import-service");
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const { eventId } = ctx.request.query;
|
|
18
|
+
|
|
19
|
+
const result = await importService.importData(file, targetContentType, eventId);
|
|
18
20
|
|
|
19
21
|
// Create appropriate message based on results
|
|
20
22
|
let message = "Import completed successfully";
|
|
@@ -349,6 +349,13 @@ module.exports = ({ strapi }) => ({
|
|
|
349
349
|
}
|
|
350
350
|
return result;
|
|
351
351
|
}
|
|
352
|
+
|
|
353
|
+
if (["corporate", "investor", "vip-guest"].includes(contentType.split(".")[1])) {
|
|
354
|
+
cleanedEntries.forEach((entry) => {
|
|
355
|
+
entry["liveLink"] = `${process.env.PREVIEW_URL}/download/live-link?participantId=${entry["documentId"]}`;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
352
359
|
const cleanedFlat = cleanedEntries.map((entry) =>
|
|
353
360
|
flattenForXLSX(entry)
|
|
354
361
|
);
|
|
@@ -13,7 +13,7 @@ const SHORTCUT_FIELDS = [
|
|
|
13
13
|
"tickerCode",
|
|
14
14
|
];
|
|
15
15
|
module.exports = ({ strapi }) => ({
|
|
16
|
-
async importData(file, targetContentType = null) {
|
|
16
|
+
async importData(file, targetContentType = null, eventId = null) {
|
|
17
17
|
let result;
|
|
18
18
|
try {
|
|
19
19
|
let importData;
|
|
@@ -32,7 +32,7 @@ module.exports = ({ strapi }) => ({
|
|
|
32
32
|
} else if (fileExtension === "xlsx" || fileExtension === "xls") {
|
|
33
33
|
importData = this.transformExcelData(filePath, targetContentType);
|
|
34
34
|
}
|
|
35
|
-
result = await this.bulkInsertData(importData);
|
|
35
|
+
result = await this.bulkInsertData(importData, eventId);
|
|
36
36
|
return result;
|
|
37
37
|
} catch (error) {
|
|
38
38
|
// Clean up uploaded file on error
|
|
@@ -147,7 +147,7 @@ module.exports = ({ strapi }) => ({
|
|
|
147
147
|
.map(([fieldName, attr]) => toCamel(fieldName));
|
|
148
148
|
},
|
|
149
149
|
|
|
150
|
-
async handleRelations(entry, contentType) {
|
|
150
|
+
async handleRelations(entry, contentType, eventId) {
|
|
151
151
|
const resolveRelationValue = async (field, value, target) => {
|
|
152
152
|
const targetAttr = strapi.contentTypes[target].attributes;
|
|
153
153
|
for (const field of SHORTCUT_FIELDS) {
|
|
@@ -156,7 +156,7 @@ module.exports = ({ strapi }) => ({
|
|
|
156
156
|
filters: { [field]: { $eq: value } },
|
|
157
157
|
});
|
|
158
158
|
if (existing) return { id: existing.id };
|
|
159
|
-
throw new Error(`Data with ${field} ${value} not found`);
|
|
159
|
+
throw new Error(`Data with ${field} ${value} not found. Cannot map to ${contentType}`);
|
|
160
160
|
}
|
|
161
161
|
return null;
|
|
162
162
|
};
|
|
@@ -170,11 +170,22 @@ module.exports = ({ strapi }) => ({
|
|
|
170
170
|
const { field, target, relation } = rel;
|
|
171
171
|
|
|
172
172
|
let value = entry[field];
|
|
173
|
-
|
|
173
|
+
|
|
174
|
+
// Excel column NOT PROVIDED → do not touch relation
|
|
175
|
+
if (value === undefined) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Excel explicitly empty → unlink
|
|
180
|
+
if (value === "") {
|
|
174
181
|
if (relation === "manyToMany" || relation === "oneToMany") {
|
|
175
182
|
updatedEntry[field] = [];
|
|
176
183
|
} else {
|
|
177
|
-
|
|
184
|
+
if (field === 'event') {
|
|
185
|
+
updatedEntry[field] = { documentId: eventId };
|
|
186
|
+
} else {
|
|
187
|
+
updatedEntry[field] = null;
|
|
188
|
+
}
|
|
178
189
|
}
|
|
179
190
|
continue;
|
|
180
191
|
}
|
|
@@ -268,11 +279,11 @@ module.exports = ({ strapi }) => ({
|
|
|
268
279
|
if (attr.type === 'component') {
|
|
269
280
|
cleaned[key] = attr.repeatable
|
|
270
281
|
? (value || []).map((v, i) =>
|
|
271
|
-
sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
|
|
282
|
+
this.sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
|
|
272
283
|
)
|
|
273
|
-
: sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
|
|
284
|
+
: this.sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
|
|
274
285
|
} else {
|
|
275
|
-
cleaned[key] = sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
|
|
286
|
+
cleaned[key] = this.sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
|
|
276
287
|
}
|
|
277
288
|
}
|
|
278
289
|
|
|
@@ -297,13 +308,13 @@ module.exports = ({ strapi }) => ({
|
|
|
297
308
|
|
|
298
309
|
cleaned[key] = attr.repeatable
|
|
299
310
|
? value.map((v, i) =>
|
|
300
|
-
sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
|
|
311
|
+
this.sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
|
|
301
312
|
)
|
|
302
|
-
: sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
|
|
313
|
+
: this.sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
|
|
303
314
|
continue;
|
|
304
315
|
}
|
|
305
316
|
|
|
306
|
-
cleaned[key] = sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
|
|
317
|
+
cleaned[key] = this.sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
|
|
307
318
|
}
|
|
308
319
|
|
|
309
320
|
return cleaned;
|
|
@@ -341,37 +352,7 @@ module.exports = ({ strapi }) => ({
|
|
|
341
352
|
}
|
|
342
353
|
},
|
|
343
354
|
|
|
344
|
-
|
|
345
|
-
const schema = strapi.contentTypes[uid];
|
|
346
|
-
const cleaned = {};
|
|
347
|
-
|
|
348
|
-
for (const [key, attr] of Object.entries(schema.attributes)) {
|
|
349
|
-
const value = data[key];
|
|
350
|
-
const fieldPath = path ? `${path}.${key}` : key;
|
|
351
|
-
|
|
352
|
-
if (value === undefined) continue;
|
|
353
|
-
|
|
354
|
-
if (attr.type === 'component') {
|
|
355
|
-
if (!value) {
|
|
356
|
-
cleaned[key] = attr.repeatable ? [] : null;
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
cleaned[key] = attr.repeatable
|
|
361
|
-
? value.map((v, i) =>
|
|
362
|
-
sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
|
|
363
|
-
)
|
|
364
|
-
: sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
cleaned[key] = sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return cleaned;
|
|
372
|
-
},
|
|
373
|
-
|
|
374
|
-
async bulkInsertData(importData) {
|
|
355
|
+
async bulkInsertData(importData, eventId) {
|
|
375
356
|
const results = {
|
|
376
357
|
created: 0,
|
|
377
358
|
updated: 0,
|
|
@@ -392,7 +373,8 @@ module.exports = ({ strapi }) => ({
|
|
|
392
373
|
try {
|
|
393
374
|
const { created, updated, errors } = await this.importEntries(
|
|
394
375
|
entries,
|
|
395
|
-
contentType
|
|
376
|
+
contentType,
|
|
377
|
+
eventId,
|
|
396
378
|
);
|
|
397
379
|
results.created += created;
|
|
398
380
|
results.updated += updated;
|
|
@@ -405,7 +387,7 @@ module.exports = ({ strapi }) => ({
|
|
|
405
387
|
return results;
|
|
406
388
|
},
|
|
407
389
|
|
|
408
|
-
async importEntries(entries, contentType) {
|
|
390
|
+
async importEntries(entries, contentType, eventId) {
|
|
409
391
|
const results = { created: 0, updated: 0, errors: [] };
|
|
410
392
|
|
|
411
393
|
await strapi.db.transaction(async ({ trx, rollback, onRollback }) => {
|
|
@@ -430,13 +412,16 @@ module.exports = ({ strapi }) => ({
|
|
|
430
412
|
},
|
|
431
413
|
{ transaction: trx }
|
|
432
414
|
);
|
|
415
|
+
if (!existing) {
|
|
416
|
+
throw new Error(`Document with id ${id} not found`);
|
|
417
|
+
}
|
|
433
418
|
}
|
|
434
419
|
|
|
435
420
|
// Handle relations & components
|
|
436
|
-
data = await this.handleRelations(data, contentType,
|
|
421
|
+
data = await this.handleRelations(data, contentType, eventId);
|
|
437
422
|
data = await this.handleComponents(data, existing, contentType);
|
|
438
423
|
const sanitizeErrors = [];
|
|
439
|
-
data = sanitizeEntryBeforeWrite(data, contentType, '', sanitizeErrors);
|
|
424
|
+
data = this.sanitizeEntryBeforeWrite(data, contentType, '', sanitizeErrors);
|
|
440
425
|
|
|
441
426
|
if (sanitizeErrors.length) {
|
|
442
427
|
throw new Error(`Data validation failed:\n${sanitizeErrors.join('\n')}`);
|
|
@@ -452,10 +437,8 @@ module.exports = ({ strapi }) => ({
|
|
|
452
437
|
{ transaction: trx }
|
|
453
438
|
);
|
|
454
439
|
results.updated++;
|
|
455
|
-
}
|
|
456
|
-
|
|
440
|
+
} else {
|
|
457
441
|
// Create
|
|
458
|
-
else {
|
|
459
442
|
await strapi
|
|
460
443
|
.documents(contentType)
|
|
461
444
|
.create({ data }, { transaction: trx });
|