strapi-plugin-bulk-updater 1.5.0 → 1.5.3
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/dist/_chunks/{BulkUpdater-CSmtXjbM.js → BulkUpdater-DMkx6dLf.js} +134 -136
- package/dist/_chunks/BulkUpdater-DMkx6dLf.js.map +1 -0
- package/dist/_chunks/{BulkUpdater-By9Dd_YF.mjs → BulkUpdater-DUfv52ng.mjs} +134 -136
- package/dist/_chunks/BulkUpdater-DUfv52ng.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +201 -40
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +201 -40
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/_chunks/BulkUpdater-By9Dd_YF.mjs.map +0 -1
- package/dist/_chunks/BulkUpdater-CSmtXjbM.js.map +0 -1
package/dist/admin/index.js
CHANGED
|
@@ -68,7 +68,7 @@ const index = {
|
|
|
68
68
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
69
69
|
defaultMessage: "Bulk Attribute Updater"
|
|
70
70
|
},
|
|
71
|
-
Component: () => Promise.resolve().then(() => require("../_chunks/BulkUpdater-
|
|
71
|
+
Component: () => Promise.resolve().then(() => require("../_chunks/BulkUpdater-DMkx6dLf.js")),
|
|
72
72
|
permissions: [],
|
|
73
73
|
position: 3
|
|
74
74
|
});
|
package/dist/admin/index.mjs
CHANGED
|
@@ -65,7 +65,7 @@ const index = {
|
|
|
65
65
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
66
66
|
defaultMessage: "Bulk Attribute Updater"
|
|
67
67
|
},
|
|
68
|
-
Component: () => import("../_chunks/BulkUpdater-
|
|
68
|
+
Component: () => import("../_chunks/BulkUpdater-DUfv52ng.mjs"),
|
|
69
69
|
permissions: [],
|
|
70
70
|
position: 3
|
|
71
71
|
});
|
package/dist/server/index.js
CHANGED
|
@@ -365,10 +365,10 @@ const bulkUpdaterController = ({ strapi }) => ({
|
|
|
365
365
|
ctx.set("ETag", data.etag);
|
|
366
366
|
ctx.set("Cache-Control", "private, no-cache");
|
|
367
367
|
}
|
|
368
|
-
ctx.body = { success: true, ...data };
|
|
368
|
+
ctx.body = { success: true, status: "success", ...data };
|
|
369
369
|
} catch (err) {
|
|
370
370
|
ctx.status = 500;
|
|
371
|
-
ctx.body = { success: false, error: err.message };
|
|
371
|
+
ctx.body = { success: false, status: "error", error: err.message };
|
|
372
372
|
}
|
|
373
373
|
},
|
|
374
374
|
async getRelationOptions(ctx) {
|
|
@@ -970,6 +970,7 @@ function formatEntryRecord(entry) {
|
|
|
970
970
|
const formatted = {
|
|
971
971
|
id: entry.id,
|
|
972
972
|
documentId: entry.documentId,
|
|
973
|
+
status: entry.status !== void 0 ? entry.status : void 0,
|
|
973
974
|
...entry
|
|
974
975
|
};
|
|
975
976
|
if (entry.updatedAt !== void 0 && formatted.updated_at === void 0) {
|
|
@@ -992,6 +993,119 @@ function formatEntryRecord(entry) {
|
|
|
992
993
|
}
|
|
993
994
|
return formatted;
|
|
994
995
|
}
|
|
996
|
+
async function populateDocumentLifecycleStatus(strapi, uid, entries) {
|
|
997
|
+
if (!entries || !Array.isArray(entries) || entries.length === 0) {
|
|
998
|
+
return entries;
|
|
999
|
+
}
|
|
1000
|
+
const contentType = strapi?.contentTypes?.[uid];
|
|
1001
|
+
if (!contentType) {
|
|
1002
|
+
return entries;
|
|
1003
|
+
}
|
|
1004
|
+
const hasDraftAndPublish = Boolean(contentType.options?.draftAndPublish);
|
|
1005
|
+
if (!hasDraftAndPublish) {
|
|
1006
|
+
for (const entry of entries) {
|
|
1007
|
+
if (entry && typeof entry === "object") {
|
|
1008
|
+
entry.status = "published";
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return entries;
|
|
1012
|
+
}
|
|
1013
|
+
const hasSlugInSchema = Boolean(contentType.attributes?.slug);
|
|
1014
|
+
const docIds = [];
|
|
1015
|
+
const slugs = [];
|
|
1016
|
+
for (const entry of entries) {
|
|
1017
|
+
if (!entry || typeof entry !== "object") continue;
|
|
1018
|
+
if (entry.documentId) {
|
|
1019
|
+
docIds.push(String(entry.documentId));
|
|
1020
|
+
} else if (hasSlugInSchema && entry.slug) {
|
|
1021
|
+
slugs.push(String(entry.slug));
|
|
1022
|
+
} else {
|
|
1023
|
+
entry.status = "unknown";
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
if (docIds.length === 0 && slugs.length === 0) {
|
|
1027
|
+
return entries;
|
|
1028
|
+
}
|
|
1029
|
+
let filterClause;
|
|
1030
|
+
if (docIds.length > 0 && slugs.length > 0) {
|
|
1031
|
+
filterClause = {
|
|
1032
|
+
$or: [
|
|
1033
|
+
{ documentId: { $in: docIds } },
|
|
1034
|
+
{ slug: { $in: slugs } }
|
|
1035
|
+
]
|
|
1036
|
+
};
|
|
1037
|
+
} else if (docIds.length > 0) {
|
|
1038
|
+
filterClause = { documentId: { $in: docIds } };
|
|
1039
|
+
} else {
|
|
1040
|
+
filterClause = { slug: { $in: slugs } };
|
|
1041
|
+
}
|
|
1042
|
+
const queryFields = ["documentId", "updatedAt", "publishedAt"];
|
|
1043
|
+
if (hasSlugInSchema) {
|
|
1044
|
+
queryFields.push("slug");
|
|
1045
|
+
}
|
|
1046
|
+
let publishedRecords = [];
|
|
1047
|
+
try {
|
|
1048
|
+
const docService = strapi?.documents?.(uid);
|
|
1049
|
+
if (docService?.findMany) {
|
|
1050
|
+
publishedRecords = await docService.findMany({
|
|
1051
|
+
status: "published",
|
|
1052
|
+
filters: filterClause,
|
|
1053
|
+
fields: queryFields,
|
|
1054
|
+
limit: Math.max(entries.length, 100)
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
} catch (err) {
|
|
1058
|
+
strapi?.log?.warn?.(`[bulk-updater] Failed to fetch published status for ${uid}: ${err?.message || err}`);
|
|
1059
|
+
for (const entry of entries) {
|
|
1060
|
+
if (entry && typeof entry === "object" && entry.status !== "unknown") {
|
|
1061
|
+
entry.status = "unknown";
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
return entries;
|
|
1065
|
+
}
|
|
1066
|
+
const publishedByDocId = /* @__PURE__ */ new Map();
|
|
1067
|
+
const publishedBySlug = /* @__PURE__ */ new Map();
|
|
1068
|
+
for (const pub of publishedRecords || []) {
|
|
1069
|
+
if (pub?.documentId) {
|
|
1070
|
+
publishedByDocId.set(String(pub.documentId), pub);
|
|
1071
|
+
}
|
|
1072
|
+
if (pub?.slug && hasSlugInSchema) {
|
|
1073
|
+
publishedBySlug.set(String(pub.slug), pub);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
for (const entry of entries) {
|
|
1077
|
+
if (!entry || typeof entry !== "object") continue;
|
|
1078
|
+
if (entry.status === "unknown") continue;
|
|
1079
|
+
const pub = entry.documentId && publishedByDocId.get(String(entry.documentId)) || hasSlugInSchema && entry.slug && publishedBySlug.get(String(entry.slug));
|
|
1080
|
+
if (!pub) {
|
|
1081
|
+
entry.status = "draft";
|
|
1082
|
+
entry.publishedAt = null;
|
|
1083
|
+
entry.published_at = null;
|
|
1084
|
+
} else {
|
|
1085
|
+
entry.publishedAt = pub.publishedAt || pub.published_at || null;
|
|
1086
|
+
entry.published_at = entry.publishedAt;
|
|
1087
|
+
const draftUpdatedTime = new Date(entry.updatedAt || entry.updated_at || 0).getTime();
|
|
1088
|
+
const pubUpdatedTime = new Date(pub.updatedAt || pub.updated_at || 0).getTime();
|
|
1089
|
+
const pubPublishedTime = new Date(pub.publishedAt || pub.published_at || 0).getTime();
|
|
1090
|
+
const lastPublishedTime = Math.max(
|
|
1091
|
+
isNaN(pubUpdatedTime) ? 0 : pubUpdatedTime,
|
|
1092
|
+
isNaN(pubPublishedTime) ? 0 : pubPublishedTime
|
|
1093
|
+
);
|
|
1094
|
+
if (isNaN(draftUpdatedTime) || lastPublishedTime === 0) {
|
|
1095
|
+
if (pub.publishedAt) {
|
|
1096
|
+
entry.status = "published";
|
|
1097
|
+
} else {
|
|
1098
|
+
entry.status = "unknown";
|
|
1099
|
+
}
|
|
1100
|
+
} else if (draftUpdatedTime > lastPublishedTime) {
|
|
1101
|
+
entry.status = "modified";
|
|
1102
|
+
} else {
|
|
1103
|
+
entry.status = "published";
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return entries;
|
|
1108
|
+
}
|
|
995
1109
|
function resolveContentTypeField(contentType, field) {
|
|
996
1110
|
if (!field) return null;
|
|
997
1111
|
const attrs = contentType?.attributes || {};
|
|
@@ -1116,14 +1230,15 @@ function discoverComponentAttributes(strapi, compUid, prefix, currentDepth, maxD
|
|
|
1116
1230
|
}
|
|
1117
1231
|
function parseDynamicZonePath(path) {
|
|
1118
1232
|
if (!path) return { cleanPath: "", rootKey: "", subPath: "" };
|
|
1119
|
-
const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\]
|
|
1233
|
+
const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\](?:\.(.+))?$/);
|
|
1120
1234
|
if (bracketMatch) {
|
|
1121
1235
|
const rootKey = bracketMatch[1];
|
|
1122
|
-
const selector = bracketMatch[2];
|
|
1123
|
-
const subPath = bracketMatch[3];
|
|
1124
|
-
const cleanPath = `${rootKey}.${subPath}
|
|
1125
|
-
|
|
1126
|
-
|
|
1236
|
+
const selector = bracketMatch[2].trim();
|
|
1237
|
+
const subPath = bracketMatch[3] || "";
|
|
1238
|
+
const cleanPath = subPath ? `${rootKey}.${subPath}` : rootKey;
|
|
1239
|
+
const numMatch = selector.match(/^#?(\d+)/);
|
|
1240
|
+
if (numMatch) {
|
|
1241
|
+
return { cleanPath, rootKey, subPath, targetIndex: parseInt(numMatch[1], 10) };
|
|
1127
1242
|
}
|
|
1128
1243
|
return { cleanPath, rootKey, subPath, targetComponentUid: selector };
|
|
1129
1244
|
}
|
|
@@ -2055,6 +2170,9 @@ const bulkUpdaterService = ({ strapi }) => {
|
|
|
2055
2170
|
isRunnerRunning = false;
|
|
2056
2171
|
}
|
|
2057
2172
|
}, 3e4);
|
|
2173
|
+
if (typeof runnerInterval.unref === "function") {
|
|
2174
|
+
runnerInterval.unref();
|
|
2175
|
+
}
|
|
2058
2176
|
}
|
|
2059
2177
|
return {
|
|
2060
2178
|
/**
|
|
@@ -2257,6 +2375,7 @@ const bulkUpdaterService = ({ strapi }) => {
|
|
|
2257
2375
|
totalCount = 0;
|
|
2258
2376
|
}
|
|
2259
2377
|
const formattedEntries = (entries || []).map(formatEntryRecord);
|
|
2378
|
+
await populateDocumentLifecycleStatus(strapi, uid, formattedEntries);
|
|
2260
2379
|
modelsCache.set(uid, {
|
|
2261
2380
|
signature,
|
|
2262
2381
|
totalCount,
|
|
@@ -2372,6 +2491,7 @@ const bulkUpdaterService = ({ strapi }) => {
|
|
|
2372
2491
|
if (!colHasAttribute) {
|
|
2373
2492
|
result = {
|
|
2374
2493
|
uid,
|
|
2494
|
+
status: "success",
|
|
2375
2495
|
displayName: contentType.info?.displayName || uid,
|
|
2376
2496
|
isSingleType,
|
|
2377
2497
|
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
@@ -2513,12 +2633,15 @@ const bulkUpdaterService = ({ strapi }) => {
|
|
|
2513
2633
|
} catch {
|
|
2514
2634
|
singleDoc = null;
|
|
2515
2635
|
}
|
|
2636
|
+
const formattedEntries = singleDoc ? [formatEntryRecord(singleDoc)] : [];
|
|
2637
|
+
await populateDocumentLifecycleStatus(strapi, uid, formattedEntries);
|
|
2516
2638
|
result = {
|
|
2517
2639
|
uid,
|
|
2640
|
+
status: "success",
|
|
2518
2641
|
displayName: contentType.info?.displayName || uid,
|
|
2519
2642
|
isSingleType: true,
|
|
2520
2643
|
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
2521
|
-
entries:
|
|
2644
|
+
entries: formattedEntries,
|
|
2522
2645
|
pagination: {
|
|
2523
2646
|
page: 1,
|
|
2524
2647
|
pageSize: 1,
|
|
@@ -2605,12 +2728,15 @@ const bulkUpdaterService = ({ strapi }) => {
|
|
|
2605
2728
|
const matchedEntries = (rawEntries || []).filter(passesDzFilter);
|
|
2606
2729
|
const totalEntries = matchedEntries.length;
|
|
2607
2730
|
const paginatedEntries = matchedEntries.slice(start, start + limit);
|
|
2731
|
+
const formattedEntries = paginatedEntries.map(formatEntryRecord);
|
|
2732
|
+
await populateDocumentLifecycleStatus(strapi, uid, formattedEntries);
|
|
2608
2733
|
result = {
|
|
2609
2734
|
uid,
|
|
2735
|
+
status: "success",
|
|
2610
2736
|
displayName: contentType.info?.displayName || uid,
|
|
2611
2737
|
isSingleType: false,
|
|
2612
2738
|
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
2613
|
-
entries:
|
|
2739
|
+
entries: formattedEntries,
|
|
2614
2740
|
pagination: {
|
|
2615
2741
|
page: currentPage,
|
|
2616
2742
|
pageSize: limit,
|
|
@@ -2634,12 +2760,15 @@ const bulkUpdaterService = ({ strapi }) => {
|
|
|
2634
2760
|
filters: Object.keys(filters).length > 0 ? filters : void 0
|
|
2635
2761
|
})
|
|
2636
2762
|
]);
|
|
2763
|
+
const formattedEntries = (entries || []).map(formatEntryRecord);
|
|
2764
|
+
await populateDocumentLifecycleStatus(strapi, uid, formattedEntries);
|
|
2637
2765
|
result = {
|
|
2638
2766
|
uid,
|
|
2767
|
+
status: "success",
|
|
2639
2768
|
displayName: contentType.info?.displayName || uid,
|
|
2640
2769
|
isSingleType: false,
|
|
2641
2770
|
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
2642
|
-
entries:
|
|
2771
|
+
entries: formattedEntries,
|
|
2643
2772
|
pagination: {
|
|
2644
2773
|
page: currentPage,
|
|
2645
2774
|
pageSize: limit,
|
|
@@ -4276,42 +4405,74 @@ const auditService = ({ strapi }) => ({
|
|
|
4276
4405
|
for (const item of diffs) {
|
|
4277
4406
|
if (item.status === "updated" && item.uid && item.documentId && item.attribute) {
|
|
4278
4407
|
try {
|
|
4408
|
+
const ct = strapi.contentTypes[item.uid];
|
|
4409
|
+
if (!ct) {
|
|
4410
|
+
throw new Error(`Content type "${item.uid}" does not exist in schema.`);
|
|
4411
|
+
}
|
|
4279
4412
|
const isRel = item.oldValue && typeof item.oldValue === "object" && item.oldValue.isRelation;
|
|
4280
4413
|
let rollbackPayload;
|
|
4281
4414
|
if (isRel) {
|
|
4282
4415
|
const oldDocIds = Array.isArray(item.oldValue.documentIds) ? item.oldValue.documentIds : [];
|
|
4283
4416
|
rollbackPayload = { set: oldDocIds };
|
|
4284
4417
|
} else {
|
|
4285
|
-
rollbackPayload = item.oldValue;
|
|
4418
|
+
rollbackPayload = item.oldValue ?? null;
|
|
4286
4419
|
}
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4420
|
+
const parsed = parseDynamicZonePath(item.attribute);
|
|
4421
|
+
const rootKey = parsed.rootKey;
|
|
4422
|
+
const rootAttrDef = ct.attributes?.[rootKey];
|
|
4423
|
+
const isComponent = rootAttrDef?.type === "component";
|
|
4424
|
+
const isDynamicZone = rootAttrDef?.type === "dynamiczone";
|
|
4425
|
+
const isNested = item.attribute.includes(".") || item.attribute.includes("[") || isComponent || isDynamicZone || isDeepComponentField(ct, strapi.components, item.attribute);
|
|
4426
|
+
let wasPublished = false;
|
|
4427
|
+
if (isNested && (isComponent || isDynamicZone || rootAttrDef)) {
|
|
4428
|
+
const populateOption = buildDeepPopulate$1(ct.attributes, strapi.components);
|
|
4429
|
+
const findOneArgs = { documentId: item.documentId };
|
|
4430
|
+
if (populateOption) {
|
|
4431
|
+
findOneArgs.populate = populateOption;
|
|
4432
|
+
}
|
|
4433
|
+
const currentDoc = await strapi.documents(item.uid).findOne(findOneArgs);
|
|
4434
|
+
if (!currentDoc) {
|
|
4435
|
+
throw new Error(`Document "${item.documentId}" not found in collection "${item.uid}".`);
|
|
4436
|
+
}
|
|
4437
|
+
wasPublished = Boolean(currentDoc?.publishedAt);
|
|
4438
|
+
const isRootDz = isDynamicZone;
|
|
4439
|
+
const existingRoot = currentDoc?.[rootKey] || (isRootDz ? [] : {});
|
|
4440
|
+
let restoredRoot;
|
|
4441
|
+
if (Array.isArray(item.dynamicZoneDiffs) && item.dynamicZoneDiffs.length > 0) {
|
|
4442
|
+
let workingRoot = existingRoot;
|
|
4443
|
+
for (const dzDiff of item.dynamicZoneDiffs) {
|
|
4444
|
+
const parsedDz = parseDynamicZonePath(dzDiff.attribute || item.attribute);
|
|
4445
|
+
const dzParts = parsedDz.cleanPath.split(".").slice(1);
|
|
4446
|
+
const targetIndexes = dzDiff.index !== void 0 ? [dzDiff.index] : parsedDz.targetIndex !== void 0 ? [parsedDz.targetIndex] : void 0;
|
|
4447
|
+
workingRoot = setDeepProperty(workingRoot, dzParts, dzDiff.oldValue ?? null, {
|
|
4448
|
+
targetIndexes,
|
|
4449
|
+
targetComponentUid: dzDiff.componentUid || parsedDz.targetComponentUid,
|
|
4450
|
+
strapi
|
|
4451
|
+
});
|
|
4452
|
+
}
|
|
4453
|
+
restoredRoot = workingRoot;
|
|
4306
4454
|
} else {
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4455
|
+
const parts = parsed.cleanPath.split(".");
|
|
4456
|
+
const pathParts = parts.slice(1);
|
|
4457
|
+
const targetIndexes = parsed.targetIndex !== void 0 ? [parsed.targetIndex] : void 0;
|
|
4458
|
+
const targetComponentUid = parsed.targetComponentUid;
|
|
4459
|
+
restoredRoot = setDeepProperty(existingRoot, pathParts, rollbackPayload, {
|
|
4460
|
+
targetIndexes,
|
|
4461
|
+
targetComponentUid,
|
|
4462
|
+
strapi
|
|
4312
4463
|
});
|
|
4313
4464
|
}
|
|
4465
|
+
await strapi.documents(item.uid).update({
|
|
4466
|
+
documentId: item.documentId,
|
|
4467
|
+
data: {
|
|
4468
|
+
[rootKey]: restoredRoot
|
|
4469
|
+
}
|
|
4470
|
+
});
|
|
4314
4471
|
} else {
|
|
4472
|
+
const currentDoc = await strapi.documents(item.uid).findOne({
|
|
4473
|
+
documentId: item.documentId
|
|
4474
|
+
});
|
|
4475
|
+
wasPublished = Boolean(currentDoc?.publishedAt);
|
|
4315
4476
|
await strapi.documents(item.uid).update({
|
|
4316
4477
|
documentId: item.documentId,
|
|
4317
4478
|
data: {
|
|
@@ -4319,13 +4480,13 @@ const auditService = ({ strapi }) => ({
|
|
|
4319
4480
|
}
|
|
4320
4481
|
});
|
|
4321
4482
|
}
|
|
4322
|
-
|
|
4323
|
-
if (ct?.options?.draftAndPublish) {
|
|
4483
|
+
if (ct?.options?.draftAndPublish && wasPublished) {
|
|
4324
4484
|
try {
|
|
4325
4485
|
await strapi.documents(item.uid).publish({
|
|
4326
4486
|
documentId: item.documentId
|
|
4327
4487
|
});
|
|
4328
|
-
} catch {
|
|
4488
|
+
} catch (publishErr) {
|
|
4489
|
+
strapi.log.warn(`[bulk-updater] Failed to auto-publish rollback for ${item.uid}/${item.documentId}:`, publishErr?.message);
|
|
4329
4490
|
}
|
|
4330
4491
|
}
|
|
4331
4492
|
try {
|
|
@@ -4333,7 +4494,7 @@ const auditService = ({ strapi }) => ({
|
|
|
4333
4494
|
uid: item.uid,
|
|
4334
4495
|
documentId: item.documentId,
|
|
4335
4496
|
userId,
|
|
4336
|
-
statusOverride: ct?.options?.draftAndPublish ? "published" : void 0
|
|
4497
|
+
statusOverride: ct?.options?.draftAndPublish ? wasPublished ? "published" : "draft" : void 0
|
|
4337
4498
|
});
|
|
4338
4499
|
} catch {
|
|
4339
4500
|
}
|