strapi-plugin-bulk-updater 1.2.10 → 1.2.12
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-EI4sKaLN.js → BulkUpdater-CQ9zGdat.js} +430 -20
- package/dist/_chunks/BulkUpdater-CQ9zGdat.js.map +1 -0
- package/dist/_chunks/{BulkUpdater-Cg9utqzm.mjs → BulkUpdater-DvCSr1vU.mjs} +430 -20
- package/dist/_chunks/BulkUpdater-DvCSr1vU.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +383 -15
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +383 -15
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/_chunks/BulkUpdater-Cg9utqzm.mjs.map +0 -1
- package/dist/_chunks/BulkUpdater-EI4sKaLN.js.map +0 -1
package/dist/admin/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const index = {
|
|
|
10
10
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
11
11
|
defaultMessage: "Bulk Attribute Updater"
|
|
12
12
|
},
|
|
13
|
-
Component: () => Promise.resolve().then(() => require("../_chunks/BulkUpdater-
|
|
13
|
+
Component: () => Promise.resolve().then(() => require("../_chunks/BulkUpdater-CQ9zGdat.js")),
|
|
14
14
|
permissions: [],
|
|
15
15
|
position: 3
|
|
16
16
|
});
|
package/dist/admin/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ const index = {
|
|
|
9
9
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
10
10
|
defaultMessage: "Bulk Attribute Updater"
|
|
11
11
|
},
|
|
12
|
-
Component: () => import("../_chunks/BulkUpdater-
|
|
12
|
+
Component: () => import("../_chunks/BulkUpdater-DvCSr1vU.mjs"),
|
|
13
13
|
permissions: [],
|
|
14
14
|
position: 3
|
|
15
15
|
});
|
package/dist/server/index.js
CHANGED
|
@@ -59,6 +59,14 @@ const routes = {
|
|
|
59
59
|
policies: []
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
|
+
{
|
|
63
|
+
method: "POST",
|
|
64
|
+
path: "/batch-publish",
|
|
65
|
+
handler: "bulkUpdater.batchPublish",
|
|
66
|
+
config: {
|
|
67
|
+
policies: []
|
|
68
|
+
}
|
|
69
|
+
},
|
|
62
70
|
{
|
|
63
71
|
method: "POST",
|
|
64
72
|
path: "/preview",
|
|
@@ -294,10 +302,6 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
294
302
|
if (data?.etag) {
|
|
295
303
|
ctx.set("ETag", data.etag);
|
|
296
304
|
ctx.set("Cache-Control", "private, no-cache");
|
|
297
|
-
if (ctx.request.headers["if-none-match"] === data.etag) {
|
|
298
|
-
ctx.status = 304;
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
305
|
}
|
|
302
306
|
ctx.body = data;
|
|
303
307
|
} catch (err) {
|
|
@@ -323,10 +327,6 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
323
327
|
if (data?.etag) {
|
|
324
328
|
ctx.set("ETag", data.etag);
|
|
325
329
|
ctx.set("Cache-Control", "private, no-cache");
|
|
326
|
-
if (ctx.request.headers["if-none-match"] === data.etag) {
|
|
327
|
-
ctx.status = 304;
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
330
|
}
|
|
331
331
|
ctx.body = { success: true, ...data };
|
|
332
332
|
} catch (err) {
|
|
@@ -361,6 +361,17 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
361
361
|
ctx.body = { success: false, error: err.message };
|
|
362
362
|
}
|
|
363
363
|
},
|
|
364
|
+
async batchPublish(ctx) {
|
|
365
|
+
try {
|
|
366
|
+
const service = strapi2.plugin("bulk-updater").service("bulkUpdater");
|
|
367
|
+
const currentUser = ctx.state.user;
|
|
368
|
+
const result = await service.batchPublish(ctx.request.body || {}, currentUser);
|
|
369
|
+
ctx.body = result;
|
|
370
|
+
} catch (err) {
|
|
371
|
+
ctx.status = 400;
|
|
372
|
+
ctx.body = { success: false, error: err.message };
|
|
373
|
+
}
|
|
374
|
+
},
|
|
364
375
|
async previewBatch(ctx) {
|
|
365
376
|
try {
|
|
366
377
|
const service = strapi2.plugin("bulk-updater").service("bulkUpdater");
|
|
@@ -1101,6 +1112,164 @@ async function executeBatchInternal(strapi2, {
|
|
|
1101
1112
|
results
|
|
1102
1113
|
};
|
|
1103
1114
|
}
|
|
1115
|
+
async function executePublishBatchInternal(strapi2, {
|
|
1116
|
+
selectedEntries = [],
|
|
1117
|
+
selectedCollections = []
|
|
1118
|
+
}, currentUser, existingBatchId) {
|
|
1119
|
+
const targetsMap = /* @__PURE__ */ new Map();
|
|
1120
|
+
for (const colUid of selectedCollections) {
|
|
1121
|
+
if (!strapi2.contentTypes[colUid]) continue;
|
|
1122
|
+
const entries = await strapi2.documents(colUid).findMany();
|
|
1123
|
+
for (const entry of entries || []) {
|
|
1124
|
+
const key = `${colUid}@@@${entry.documentId}`;
|
|
1125
|
+
targetsMap.set(key, { uid: colUid, documentId: entry.documentId });
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
for (const item of selectedEntries) {
|
|
1129
|
+
if (!item.uid || !item.documentId) continue;
|
|
1130
|
+
const key = `${item.uid}@@@${item.documentId}`;
|
|
1131
|
+
targetsMap.set(key, { uid: item.uid, documentId: item.documentId });
|
|
1132
|
+
}
|
|
1133
|
+
if (targetsMap.size === 0) {
|
|
1134
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
1135
|
+
}
|
|
1136
|
+
const batchId = existingBatchId || `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
1137
|
+
const results = [];
|
|
1138
|
+
let publishedCount = 0;
|
|
1139
|
+
let skippedCount = 0;
|
|
1140
|
+
const jobState = {
|
|
1141
|
+
id: batchId,
|
|
1142
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1143
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1144
|
+
createdBy: currentUser ? {
|
|
1145
|
+
id: currentUser.id,
|
|
1146
|
+
email: currentUser.email,
|
|
1147
|
+
firstname: currentUser.firstname,
|
|
1148
|
+
lastname: currentUser.lastname,
|
|
1149
|
+
username: currentUser.username
|
|
1150
|
+
} : { email: "admin@system.local" },
|
|
1151
|
+
status: "processing",
|
|
1152
|
+
executionMode: "immediate",
|
|
1153
|
+
attribute: "(publish)",
|
|
1154
|
+
value: "published",
|
|
1155
|
+
totalTargets: targetsMap.size,
|
|
1156
|
+
processedCount: 0,
|
|
1157
|
+
updatedCount: 0,
|
|
1158
|
+
skippedCount: 0,
|
|
1159
|
+
failedCount: 0,
|
|
1160
|
+
isLive: false,
|
|
1161
|
+
publishOnApproval: true,
|
|
1162
|
+
results: []
|
|
1163
|
+
};
|
|
1164
|
+
batchJobsMap.set(batchId, jobState);
|
|
1165
|
+
const targets = Array.from(targetsMap.values());
|
|
1166
|
+
const CHUNK_SIZE = 25;
|
|
1167
|
+
for (let i = 0; i < targets.length; i += CHUNK_SIZE) {
|
|
1168
|
+
const chunk = targets.slice(i, i + CHUNK_SIZE);
|
|
1169
|
+
const chunkPromises = chunk.map(async (target) => {
|
|
1170
|
+
try {
|
|
1171
|
+
const contentType = strapi2.contentTypes[target.uid];
|
|
1172
|
+
const displayName = contentType?.info?.displayName || target.uid;
|
|
1173
|
+
const isDraftAndPublish = Boolean(contentType?.options?.draftAndPublish);
|
|
1174
|
+
let existingDoc = null;
|
|
1175
|
+
try {
|
|
1176
|
+
existingDoc = await strapi2.documents(target.uid).findOne({
|
|
1177
|
+
documentId: target.documentId
|
|
1178
|
+
});
|
|
1179
|
+
} catch {
|
|
1180
|
+
existingDoc = null;
|
|
1181
|
+
}
|
|
1182
|
+
const entryLabel = existingDoc?.name || existingDoc?.title || existingDoc?.label || existingDoc?.documentId || `Entry #${target.documentId}`;
|
|
1183
|
+
if (!isDraftAndPublish) {
|
|
1184
|
+
return {
|
|
1185
|
+
uid: target.uid,
|
|
1186
|
+
collectionName: displayName,
|
|
1187
|
+
documentId: target.documentId,
|
|
1188
|
+
label: entryLabel,
|
|
1189
|
+
attribute: "(publish)",
|
|
1190
|
+
status: "skipped",
|
|
1191
|
+
message: `Skipped: Draft & Publish is disabled for collection ${displayName}`
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
const isAlreadyPublished = Boolean(existingDoc?.publishedAt);
|
|
1195
|
+
await strapi2.documents(target.uid).publish({
|
|
1196
|
+
documentId: target.documentId
|
|
1197
|
+
});
|
|
1198
|
+
invalidateCollectionCache(target.uid);
|
|
1199
|
+
return {
|
|
1200
|
+
uid: target.uid,
|
|
1201
|
+
collectionName: displayName,
|
|
1202
|
+
documentId: target.documentId,
|
|
1203
|
+
label: entryLabel,
|
|
1204
|
+
attribute: "(publish)",
|
|
1205
|
+
oldValue: isAlreadyPublished ? "published" : "draft",
|
|
1206
|
+
newValue: "published",
|
|
1207
|
+
status: "updated",
|
|
1208
|
+
message: isAlreadyPublished ? "Re-published latest version live" : "Successfully published to live"
|
|
1209
|
+
};
|
|
1210
|
+
} catch (pubErr) {
|
|
1211
|
+
return {
|
|
1212
|
+
uid: target.uid,
|
|
1213
|
+
collectionName: strapi2.contentTypes[target.uid]?.info?.displayName || target.uid,
|
|
1214
|
+
documentId: target.documentId,
|
|
1215
|
+
label: `Entry #${target.documentId}`,
|
|
1216
|
+
attribute: "(publish)",
|
|
1217
|
+
status: "error",
|
|
1218
|
+
message: pubErr.message || "Failed to publish entry"
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
const chunkResults = await Promise.all(chunkPromises);
|
|
1223
|
+
for (const res of chunkResults) {
|
|
1224
|
+
if (res.status === "updated") publishedCount++;
|
|
1225
|
+
else if (res.status === "skipped") skippedCount++;
|
|
1226
|
+
results.push(res);
|
|
1227
|
+
}
|
|
1228
|
+
jobState.processedCount = results.length;
|
|
1229
|
+
jobState.updatedCount = publishedCount;
|
|
1230
|
+
jobState.skippedCount = skippedCount;
|
|
1231
|
+
jobState.failedCount = results.filter((r) => r.status === "error").length;
|
|
1232
|
+
}
|
|
1233
|
+
const affectedUids = new Set(targets.map((t) => t.uid));
|
|
1234
|
+
affectedUids.forEach((uid) => {
|
|
1235
|
+
invalidateCollectionCache(uid);
|
|
1236
|
+
});
|
|
1237
|
+
const failedCount = results.filter((r) => r.status === "error").length;
|
|
1238
|
+
jobState.failedCount = failedCount;
|
|
1239
|
+
jobState.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1240
|
+
jobState.isLive = publishedCount > 0;
|
|
1241
|
+
jobState.status = failedCount === 0 && publishedCount > 0 ? "successful" : failedCount > 0 && publishedCount > 0 ? "partial_failure" : failedCount > 0 ? "failed" : "successful";
|
|
1242
|
+
jobState.results = results.map((r) => ({
|
|
1243
|
+
...r,
|
|
1244
|
+
isLive: r.status === "updated"
|
|
1245
|
+
}));
|
|
1246
|
+
const batchSummary = {
|
|
1247
|
+
batchId,
|
|
1248
|
+
attribute: "(publish)",
|
|
1249
|
+
value: "published",
|
|
1250
|
+
updatedCount: publishedCount,
|
|
1251
|
+
skippedCount,
|
|
1252
|
+
totalTargets: targetsMap.size,
|
|
1253
|
+
publishOnApproval: true
|
|
1254
|
+
};
|
|
1255
|
+
await strapi2.plugin("bulk-updater").service("audit").recordBatch(
|
|
1256
|
+
batchSummary,
|
|
1257
|
+
results,
|
|
1258
|
+
currentUser
|
|
1259
|
+
);
|
|
1260
|
+
return {
|
|
1261
|
+
success: true,
|
|
1262
|
+
batchId,
|
|
1263
|
+
publishedCount,
|
|
1264
|
+
updatedCount: publishedCount,
|
|
1265
|
+
skippedCount,
|
|
1266
|
+
failedCount,
|
|
1267
|
+
totalTargets: targetsMap.size,
|
|
1268
|
+
isLive: publishedCount > 0,
|
|
1269
|
+
status: jobState.status,
|
|
1270
|
+
results
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1104
1273
|
const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
1105
1274
|
if (!runnerInterval) {
|
|
1106
1275
|
runnerInterval = setInterval(async () => {
|
|
@@ -1112,7 +1281,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1112
1281
|
for (const [id, batch] of pendingBatches.entries()) {
|
|
1113
1282
|
if (batch.status === "queued_offpeak" && !isBusinessHours) {
|
|
1114
1283
|
strapi2.log.info(`[bulk-updater] Executing off-peak queued batch: ${id}`);
|
|
1115
|
-
const result = await executeBatchInternal(strapi2, batch.payload, batch.createdBy, id);
|
|
1284
|
+
const result = batch.payload?.action === "publish" ? await executePublishBatchInternal(strapi2, batch.payload, batch.createdBy, id) : await executeBatchInternal(strapi2, batch.payload, batch.createdBy, id);
|
|
1116
1285
|
batch.status = "executed";
|
|
1117
1286
|
batch.executionResult = result;
|
|
1118
1287
|
}
|
|
@@ -1209,6 +1378,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1209
1378
|
uid,
|
|
1210
1379
|
kind: contentType.kind,
|
|
1211
1380
|
isSingleType,
|
|
1381
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1212
1382
|
singularName: contentType.info?.singularName || uid,
|
|
1213
1383
|
pluralName: contentType.info?.pluralName || uid,
|
|
1214
1384
|
displayName: contentType.info?.displayName || uid,
|
|
@@ -1390,6 +1560,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1390
1560
|
uid,
|
|
1391
1561
|
displayName: contentType.info?.displayName || uid,
|
|
1392
1562
|
isSingleType,
|
|
1563
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1393
1564
|
entries: [],
|
|
1394
1565
|
pagination: {
|
|
1395
1566
|
page: 1,
|
|
@@ -1403,10 +1574,12 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1403
1574
|
}
|
|
1404
1575
|
let condition = void 0;
|
|
1405
1576
|
const q = (filterQuery || "").trim();
|
|
1577
|
+
const targetAttrSchema = isNestedAttr ? strapi2.components[attrs[parentKey]?.component]?.attributes?.[childKey] : attrs[attribute];
|
|
1578
|
+
const isStringLike = ["string", "text", "email", "richtext", "uid"].includes(targetAttrSchema?.type);
|
|
1406
1579
|
if (normOp === "empty") {
|
|
1407
|
-
condition = { $or: [{ $null: true }, { $eq: "" }] };
|
|
1580
|
+
condition = isStringLike ? { $or: [{ $null: true }, { $eq: "" }] } : { $null: true };
|
|
1408
1581
|
} else if (normOp === "notempty") {
|
|
1409
|
-
condition = { $and: [{ $notNull: true }, { $ne: "" }] };
|
|
1582
|
+
condition = isStringLike ? { $and: [{ $notNull: true }, { $ne: "" }] } : { $notNull: true };
|
|
1410
1583
|
} else if (q !== "") {
|
|
1411
1584
|
switch (normOp) {
|
|
1412
1585
|
case "equals":
|
|
@@ -1435,12 +1608,12 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1435
1608
|
[childKey]: condition
|
|
1436
1609
|
};
|
|
1437
1610
|
} else {
|
|
1438
|
-
if (normOp === "empty") {
|
|
1611
|
+
if (normOp === "empty" && isStringLike) {
|
|
1439
1612
|
filters2.$or = [
|
|
1440
1613
|
{ [attribute]: { $null: true } },
|
|
1441
1614
|
{ [attribute]: { $eq: "" } }
|
|
1442
1615
|
];
|
|
1443
|
-
} else if (normOp === "notempty") {
|
|
1616
|
+
} else if (normOp === "notempty" && isStringLike) {
|
|
1444
1617
|
filters2[attribute] = { $notNull: true, $ne: "" };
|
|
1445
1618
|
} else {
|
|
1446
1619
|
filters2[attribute] = condition;
|
|
@@ -1479,6 +1652,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1479
1652
|
uid,
|
|
1480
1653
|
displayName: contentType.info?.displayName || uid,
|
|
1481
1654
|
isSingleType: true,
|
|
1655
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1482
1656
|
entries: singleDoc ? [singleDoc] : [],
|
|
1483
1657
|
pagination: {
|
|
1484
1658
|
page: 1,
|
|
@@ -1522,6 +1696,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1522
1696
|
uid,
|
|
1523
1697
|
displayName: contentType.info?.displayName || uid,
|
|
1524
1698
|
isSingleType: false,
|
|
1699
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1525
1700
|
entries: (entries || []).map((entry) => ({
|
|
1526
1701
|
id: entry.id,
|
|
1527
1702
|
documentId: entry.documentId,
|
|
@@ -2022,6 +2197,199 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
2022
2197
|
currentUser
|
|
2023
2198
|
);
|
|
2024
2199
|
},
|
|
2200
|
+
/**
|
|
2201
|
+
* Bulk Publish selected entries or collections
|
|
2202
|
+
*/
|
|
2203
|
+
async batchPublish({
|
|
2204
|
+
selectedEntries = [],
|
|
2205
|
+
selectedCollections = [],
|
|
2206
|
+
executionMode = "immediate",
|
|
2207
|
+
makerNotes = "",
|
|
2208
|
+
forceImmediate = false
|
|
2209
|
+
}, currentUser) {
|
|
2210
|
+
const executionConfig = getExecutionWindowConfig(strapi2);
|
|
2211
|
+
const { isBusinessHours, policyMessage } = checkBusinessHours(executionConfig);
|
|
2212
|
+
if (executionMode === "maker_checker") {
|
|
2213
|
+
const summary = await computeTargetsSummary(strapi2, { selectedCollections, selectedEntries });
|
|
2214
|
+
if (summary.totalTargets === 0) {
|
|
2215
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
2216
|
+
}
|
|
2217
|
+
const batchId = `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2218
|
+
const batch = {
|
|
2219
|
+
id: batchId,
|
|
2220
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2221
|
+
createdBy: currentUser ? {
|
|
2222
|
+
id: currentUser.id,
|
|
2223
|
+
email: currentUser.email,
|
|
2224
|
+
firstname: currentUser.firstname,
|
|
2225
|
+
lastname: currentUser.lastname,
|
|
2226
|
+
username: currentUser.username
|
|
2227
|
+
} : { email: "admin@system.local" },
|
|
2228
|
+
payload: { action: "publish", attribute: "(publish)", value: "published", selectedEntries, selectedCollections, publishOnApproval: true },
|
|
2229
|
+
summary: {
|
|
2230
|
+
attribute: "(publish)",
|
|
2231
|
+
value: "published",
|
|
2232
|
+
totalTargets: summary.totalTargets,
|
|
2233
|
+
collectionBreakdown: summary.collectionBreakdown,
|
|
2234
|
+
publishOnApproval: true
|
|
2235
|
+
},
|
|
2236
|
+
status: "pending_approval",
|
|
2237
|
+
executionMode: "maker_checker",
|
|
2238
|
+
makerNotes
|
|
2239
|
+
};
|
|
2240
|
+
pendingBatches.set(batchId, batch);
|
|
2241
|
+
batchJobsMap.set(batchId, {
|
|
2242
|
+
id: batchId,
|
|
2243
|
+
createdAt: batch.createdAt,
|
|
2244
|
+
createdBy: batch.createdBy,
|
|
2245
|
+
status: "pending_approval",
|
|
2246
|
+
executionMode: "maker_checker",
|
|
2247
|
+
attribute: "(publish)",
|
|
2248
|
+
value: "published",
|
|
2249
|
+
totalTargets: summary.totalTargets,
|
|
2250
|
+
processedCount: 0,
|
|
2251
|
+
updatedCount: 0,
|
|
2252
|
+
skippedCount: 0,
|
|
2253
|
+
failedCount: 0,
|
|
2254
|
+
isLive: false,
|
|
2255
|
+
publishOnApproval: true,
|
|
2256
|
+
makerNotes,
|
|
2257
|
+
results: []
|
|
2258
|
+
});
|
|
2259
|
+
return {
|
|
2260
|
+
success: true,
|
|
2261
|
+
pending: true,
|
|
2262
|
+
batchId,
|
|
2263
|
+
status: "pending_approval",
|
|
2264
|
+
message: "Bulk publish batch submitted for Checker authorization (4-Eyes Maker-Checker Workflow).",
|
|
2265
|
+
batch
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
if (executionMode === "queue_offpeak") {
|
|
2269
|
+
const summary = await computeTargetsSummary(strapi2, { selectedCollections, selectedEntries });
|
|
2270
|
+
if (summary.totalTargets === 0) {
|
|
2271
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
2272
|
+
}
|
|
2273
|
+
const batchId = `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2274
|
+
const batch = {
|
|
2275
|
+
id: batchId,
|
|
2276
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2277
|
+
createdBy: currentUser ? {
|
|
2278
|
+
id: currentUser.id,
|
|
2279
|
+
email: currentUser.email,
|
|
2280
|
+
firstname: currentUser.firstname,
|
|
2281
|
+
lastname: currentUser.lastname,
|
|
2282
|
+
username: currentUser.username
|
|
2283
|
+
} : { email: "admin@system.local" },
|
|
2284
|
+
payload: { action: "publish", attribute: "(publish)", value: "published", selectedEntries, selectedCollections, publishOnApproval: true },
|
|
2285
|
+
summary: {
|
|
2286
|
+
attribute: "(publish)",
|
|
2287
|
+
value: "published",
|
|
2288
|
+
totalTargets: summary.totalTargets,
|
|
2289
|
+
collectionBreakdown: summary.collectionBreakdown,
|
|
2290
|
+
publishOnApproval: true
|
|
2291
|
+
},
|
|
2292
|
+
status: "queued_offpeak",
|
|
2293
|
+
executionMode: "queue_offpeak",
|
|
2294
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2295
|
+
makerNotes
|
|
2296
|
+
};
|
|
2297
|
+
pendingBatches.set(batchId, batch);
|
|
2298
|
+
batchJobsMap.set(batchId, {
|
|
2299
|
+
id: batchId,
|
|
2300
|
+
createdAt: batch.createdAt,
|
|
2301
|
+
createdBy: batch.createdBy,
|
|
2302
|
+
status: "queued_offpeak",
|
|
2303
|
+
executionMode: "queue_offpeak",
|
|
2304
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2305
|
+
attribute: "(publish)",
|
|
2306
|
+
value: "published",
|
|
2307
|
+
totalTargets: summary.totalTargets,
|
|
2308
|
+
processedCount: 0,
|
|
2309
|
+
updatedCount: 0,
|
|
2310
|
+
skippedCount: 0,
|
|
2311
|
+
failedCount: 0,
|
|
2312
|
+
isLive: false,
|
|
2313
|
+
publishOnApproval: true,
|
|
2314
|
+
makerNotes,
|
|
2315
|
+
results: []
|
|
2316
|
+
});
|
|
2317
|
+
return {
|
|
2318
|
+
success: true,
|
|
2319
|
+
pending: true,
|
|
2320
|
+
batchId,
|
|
2321
|
+
status: "queued_offpeak",
|
|
2322
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2323
|
+
message: `Bulk publish batch queued for server off-peak maintenance window (${executionConfig.offPeakStartTime}).`,
|
|
2324
|
+
batch
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
if (executionConfig.enabled && executionConfig.autoQueueDuringBusinessHours && isBusinessHours && !forceImmediate) {
|
|
2328
|
+
const summary = await computeTargetsSummary(strapi2, { selectedCollections, selectedEntries });
|
|
2329
|
+
if (summary.totalTargets === 0) {
|
|
2330
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
2331
|
+
}
|
|
2332
|
+
const batchId = `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2333
|
+
const batch = {
|
|
2334
|
+
id: batchId,
|
|
2335
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2336
|
+
createdBy: currentUser ? {
|
|
2337
|
+
id: currentUser.id,
|
|
2338
|
+
email: currentUser.email,
|
|
2339
|
+
firstname: currentUser.firstname,
|
|
2340
|
+
lastname: currentUser.lastname,
|
|
2341
|
+
username: currentUser.username
|
|
2342
|
+
} : { email: "admin@system.local" },
|
|
2343
|
+
payload: { action: "publish", attribute: "(publish)", value: "published", selectedEntries, selectedCollections, publishOnApproval: true },
|
|
2344
|
+
summary: {
|
|
2345
|
+
attribute: "(publish)",
|
|
2346
|
+
value: "published",
|
|
2347
|
+
totalTargets: summary.totalTargets,
|
|
2348
|
+
collectionBreakdown: summary.collectionBreakdown,
|
|
2349
|
+
publishOnApproval: true
|
|
2350
|
+
},
|
|
2351
|
+
status: "queued_offpeak",
|
|
2352
|
+
executionMode: "queue_offpeak",
|
|
2353
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2354
|
+
makerNotes: "Automatically queued due to peak business hours restriction."
|
|
2355
|
+
};
|
|
2356
|
+
pendingBatches.set(batchId, batch);
|
|
2357
|
+
batchJobsMap.set(batchId, {
|
|
2358
|
+
id: batchId,
|
|
2359
|
+
createdAt: batch.createdAt,
|
|
2360
|
+
createdBy: batch.createdBy,
|
|
2361
|
+
status: "queued_offpeak",
|
|
2362
|
+
executionMode: "queue_offpeak",
|
|
2363
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2364
|
+
attribute: "(publish)",
|
|
2365
|
+
value: "published",
|
|
2366
|
+
totalTargets: summary.totalTargets,
|
|
2367
|
+
processedCount: 0,
|
|
2368
|
+
updatedCount: 0,
|
|
2369
|
+
skippedCount: 0,
|
|
2370
|
+
failedCount: 0,
|
|
2371
|
+
isLive: false,
|
|
2372
|
+
publishOnApproval: true,
|
|
2373
|
+
policyMessage,
|
|
2374
|
+
makerNotes: "Automatically queued due to peak business hours restriction.",
|
|
2375
|
+
results: []
|
|
2376
|
+
});
|
|
2377
|
+
return {
|
|
2378
|
+
success: true,
|
|
2379
|
+
pending: true,
|
|
2380
|
+
batchId,
|
|
2381
|
+
status: "queued_offpeak",
|
|
2382
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2383
|
+
message: policyMessage,
|
|
2384
|
+
batch
|
|
2385
|
+
};
|
|
2386
|
+
}
|
|
2387
|
+
return await executePublishBatchInternal(
|
|
2388
|
+
strapi2,
|
|
2389
|
+
{ selectedEntries, selectedCollections },
|
|
2390
|
+
currentUser
|
|
2391
|
+
);
|
|
2392
|
+
},
|
|
2025
2393
|
/**
|
|
2026
2394
|
* Get Pending & Queued Batches
|
|
2027
2395
|
*/
|
|
@@ -2065,7 +2433,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
2065
2433
|
const { isBusinessHours } = checkBusinessHours(config);
|
|
2066
2434
|
if (options.executeImmediately || !isBusinessHours) {
|
|
2067
2435
|
batch.status = "approved";
|
|
2068
|
-
const result = await executeBatchInternal(strapi2, batch.payload, checkerUser, batch.id);
|
|
2436
|
+
const result = batch.payload?.action === "publish" ? await executePublishBatchInternal(strapi2, batch.payload, checkerUser, batch.id) : await executeBatchInternal(strapi2, batch.payload, checkerUser, batch.id);
|
|
2069
2437
|
batch.status = "executed";
|
|
2070
2438
|
batch.executionResult = result;
|
|
2071
2439
|
return {
|
|
@@ -2126,7 +2494,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
2126
2494
|
if (batch.status === "executed") {
|
|
2127
2495
|
throw new Error(`Batch ${batchId} has already been executed.`);
|
|
2128
2496
|
}
|
|
2129
|
-
const result = await executeBatchInternal(strapi2, batch.payload, currentUser, batch.id);
|
|
2497
|
+
const result = batch.payload?.action === "publish" ? await executePublishBatchInternal(strapi2, batch.payload, currentUser, batch.id) : await executeBatchInternal(strapi2, batch.payload, currentUser, batch.id);
|
|
2130
2498
|
batch.status = "executed";
|
|
2131
2499
|
batch.executionResult = result;
|
|
2132
2500
|
return {
|