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/server/index.mjs
CHANGED
|
@@ -46,6 +46,14 @@ const routes = {
|
|
|
46
46
|
policies: []
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
method: "POST",
|
|
51
|
+
path: "/batch-publish",
|
|
52
|
+
handler: "bulkUpdater.batchPublish",
|
|
53
|
+
config: {
|
|
54
|
+
policies: []
|
|
55
|
+
}
|
|
56
|
+
},
|
|
49
57
|
{
|
|
50
58
|
method: "POST",
|
|
51
59
|
path: "/preview",
|
|
@@ -281,10 +289,6 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
281
289
|
if (data?.etag) {
|
|
282
290
|
ctx.set("ETag", data.etag);
|
|
283
291
|
ctx.set("Cache-Control", "private, no-cache");
|
|
284
|
-
if (ctx.request.headers["if-none-match"] === data.etag) {
|
|
285
|
-
ctx.status = 304;
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
292
|
}
|
|
289
293
|
ctx.body = data;
|
|
290
294
|
} catch (err) {
|
|
@@ -310,10 +314,6 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
310
314
|
if (data?.etag) {
|
|
311
315
|
ctx.set("ETag", data.etag);
|
|
312
316
|
ctx.set("Cache-Control", "private, no-cache");
|
|
313
|
-
if (ctx.request.headers["if-none-match"] === data.etag) {
|
|
314
|
-
ctx.status = 304;
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
317
|
}
|
|
318
318
|
ctx.body = { success: true, ...data };
|
|
319
319
|
} catch (err) {
|
|
@@ -348,6 +348,17 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
348
348
|
ctx.body = { success: false, error: err.message };
|
|
349
349
|
}
|
|
350
350
|
},
|
|
351
|
+
async batchPublish(ctx) {
|
|
352
|
+
try {
|
|
353
|
+
const service = strapi2.plugin("bulk-updater").service("bulkUpdater");
|
|
354
|
+
const currentUser = ctx.state.user;
|
|
355
|
+
const result = await service.batchPublish(ctx.request.body || {}, currentUser);
|
|
356
|
+
ctx.body = result;
|
|
357
|
+
} catch (err) {
|
|
358
|
+
ctx.status = 400;
|
|
359
|
+
ctx.body = { success: false, error: err.message };
|
|
360
|
+
}
|
|
361
|
+
},
|
|
351
362
|
async previewBatch(ctx) {
|
|
352
363
|
try {
|
|
353
364
|
const service = strapi2.plugin("bulk-updater").service("bulkUpdater");
|
|
@@ -1088,6 +1099,164 @@ async function executeBatchInternal(strapi2, {
|
|
|
1088
1099
|
results
|
|
1089
1100
|
};
|
|
1090
1101
|
}
|
|
1102
|
+
async function executePublishBatchInternal(strapi2, {
|
|
1103
|
+
selectedEntries = [],
|
|
1104
|
+
selectedCollections = []
|
|
1105
|
+
}, currentUser, existingBatchId) {
|
|
1106
|
+
const targetsMap = /* @__PURE__ */ new Map();
|
|
1107
|
+
for (const colUid of selectedCollections) {
|
|
1108
|
+
if (!strapi2.contentTypes[colUid]) continue;
|
|
1109
|
+
const entries = await strapi2.documents(colUid).findMany();
|
|
1110
|
+
for (const entry of entries || []) {
|
|
1111
|
+
const key = `${colUid}@@@${entry.documentId}`;
|
|
1112
|
+
targetsMap.set(key, { uid: colUid, documentId: entry.documentId });
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
for (const item of selectedEntries) {
|
|
1116
|
+
if (!item.uid || !item.documentId) continue;
|
|
1117
|
+
const key = `${item.uid}@@@${item.documentId}`;
|
|
1118
|
+
targetsMap.set(key, { uid: item.uid, documentId: item.documentId });
|
|
1119
|
+
}
|
|
1120
|
+
if (targetsMap.size === 0) {
|
|
1121
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
1122
|
+
}
|
|
1123
|
+
const batchId = existingBatchId || `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
1124
|
+
const results = [];
|
|
1125
|
+
let publishedCount = 0;
|
|
1126
|
+
let skippedCount = 0;
|
|
1127
|
+
const jobState = {
|
|
1128
|
+
id: batchId,
|
|
1129
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1130
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1131
|
+
createdBy: currentUser ? {
|
|
1132
|
+
id: currentUser.id,
|
|
1133
|
+
email: currentUser.email,
|
|
1134
|
+
firstname: currentUser.firstname,
|
|
1135
|
+
lastname: currentUser.lastname,
|
|
1136
|
+
username: currentUser.username
|
|
1137
|
+
} : { email: "admin@system.local" },
|
|
1138
|
+
status: "processing",
|
|
1139
|
+
executionMode: "immediate",
|
|
1140
|
+
attribute: "(publish)",
|
|
1141
|
+
value: "published",
|
|
1142
|
+
totalTargets: targetsMap.size,
|
|
1143
|
+
processedCount: 0,
|
|
1144
|
+
updatedCount: 0,
|
|
1145
|
+
skippedCount: 0,
|
|
1146
|
+
failedCount: 0,
|
|
1147
|
+
isLive: false,
|
|
1148
|
+
publishOnApproval: true,
|
|
1149
|
+
results: []
|
|
1150
|
+
};
|
|
1151
|
+
batchJobsMap.set(batchId, jobState);
|
|
1152
|
+
const targets = Array.from(targetsMap.values());
|
|
1153
|
+
const CHUNK_SIZE = 25;
|
|
1154
|
+
for (let i = 0; i < targets.length; i += CHUNK_SIZE) {
|
|
1155
|
+
const chunk = targets.slice(i, i + CHUNK_SIZE);
|
|
1156
|
+
const chunkPromises = chunk.map(async (target) => {
|
|
1157
|
+
try {
|
|
1158
|
+
const contentType = strapi2.contentTypes[target.uid];
|
|
1159
|
+
const displayName = contentType?.info?.displayName || target.uid;
|
|
1160
|
+
const isDraftAndPublish = Boolean(contentType?.options?.draftAndPublish);
|
|
1161
|
+
let existingDoc = null;
|
|
1162
|
+
try {
|
|
1163
|
+
existingDoc = await strapi2.documents(target.uid).findOne({
|
|
1164
|
+
documentId: target.documentId
|
|
1165
|
+
});
|
|
1166
|
+
} catch {
|
|
1167
|
+
existingDoc = null;
|
|
1168
|
+
}
|
|
1169
|
+
const entryLabel = existingDoc?.name || existingDoc?.title || existingDoc?.label || existingDoc?.documentId || `Entry #${target.documentId}`;
|
|
1170
|
+
if (!isDraftAndPublish) {
|
|
1171
|
+
return {
|
|
1172
|
+
uid: target.uid,
|
|
1173
|
+
collectionName: displayName,
|
|
1174
|
+
documentId: target.documentId,
|
|
1175
|
+
label: entryLabel,
|
|
1176
|
+
attribute: "(publish)",
|
|
1177
|
+
status: "skipped",
|
|
1178
|
+
message: `Skipped: Draft & Publish is disabled for collection ${displayName}`
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
const isAlreadyPublished = Boolean(existingDoc?.publishedAt);
|
|
1182
|
+
await strapi2.documents(target.uid).publish({
|
|
1183
|
+
documentId: target.documentId
|
|
1184
|
+
});
|
|
1185
|
+
invalidateCollectionCache(target.uid);
|
|
1186
|
+
return {
|
|
1187
|
+
uid: target.uid,
|
|
1188
|
+
collectionName: displayName,
|
|
1189
|
+
documentId: target.documentId,
|
|
1190
|
+
label: entryLabel,
|
|
1191
|
+
attribute: "(publish)",
|
|
1192
|
+
oldValue: isAlreadyPublished ? "published" : "draft",
|
|
1193
|
+
newValue: "published",
|
|
1194
|
+
status: "updated",
|
|
1195
|
+
message: isAlreadyPublished ? "Re-published latest version live" : "Successfully published to live"
|
|
1196
|
+
};
|
|
1197
|
+
} catch (pubErr) {
|
|
1198
|
+
return {
|
|
1199
|
+
uid: target.uid,
|
|
1200
|
+
collectionName: strapi2.contentTypes[target.uid]?.info?.displayName || target.uid,
|
|
1201
|
+
documentId: target.documentId,
|
|
1202
|
+
label: `Entry #${target.documentId}`,
|
|
1203
|
+
attribute: "(publish)",
|
|
1204
|
+
status: "error",
|
|
1205
|
+
message: pubErr.message || "Failed to publish entry"
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
1209
|
+
const chunkResults = await Promise.all(chunkPromises);
|
|
1210
|
+
for (const res of chunkResults) {
|
|
1211
|
+
if (res.status === "updated") publishedCount++;
|
|
1212
|
+
else if (res.status === "skipped") skippedCount++;
|
|
1213
|
+
results.push(res);
|
|
1214
|
+
}
|
|
1215
|
+
jobState.processedCount = results.length;
|
|
1216
|
+
jobState.updatedCount = publishedCount;
|
|
1217
|
+
jobState.skippedCount = skippedCount;
|
|
1218
|
+
jobState.failedCount = results.filter((r) => r.status === "error").length;
|
|
1219
|
+
}
|
|
1220
|
+
const affectedUids = new Set(targets.map((t) => t.uid));
|
|
1221
|
+
affectedUids.forEach((uid) => {
|
|
1222
|
+
invalidateCollectionCache(uid);
|
|
1223
|
+
});
|
|
1224
|
+
const failedCount = results.filter((r) => r.status === "error").length;
|
|
1225
|
+
jobState.failedCount = failedCount;
|
|
1226
|
+
jobState.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1227
|
+
jobState.isLive = publishedCount > 0;
|
|
1228
|
+
jobState.status = failedCount === 0 && publishedCount > 0 ? "successful" : failedCount > 0 && publishedCount > 0 ? "partial_failure" : failedCount > 0 ? "failed" : "successful";
|
|
1229
|
+
jobState.results = results.map((r) => ({
|
|
1230
|
+
...r,
|
|
1231
|
+
isLive: r.status === "updated"
|
|
1232
|
+
}));
|
|
1233
|
+
const batchSummary = {
|
|
1234
|
+
batchId,
|
|
1235
|
+
attribute: "(publish)",
|
|
1236
|
+
value: "published",
|
|
1237
|
+
updatedCount: publishedCount,
|
|
1238
|
+
skippedCount,
|
|
1239
|
+
totalTargets: targetsMap.size,
|
|
1240
|
+
publishOnApproval: true
|
|
1241
|
+
};
|
|
1242
|
+
await strapi2.plugin("bulk-updater").service("audit").recordBatch(
|
|
1243
|
+
batchSummary,
|
|
1244
|
+
results,
|
|
1245
|
+
currentUser
|
|
1246
|
+
);
|
|
1247
|
+
return {
|
|
1248
|
+
success: true,
|
|
1249
|
+
batchId,
|
|
1250
|
+
publishedCount,
|
|
1251
|
+
updatedCount: publishedCount,
|
|
1252
|
+
skippedCount,
|
|
1253
|
+
failedCount,
|
|
1254
|
+
totalTargets: targetsMap.size,
|
|
1255
|
+
isLive: publishedCount > 0,
|
|
1256
|
+
status: jobState.status,
|
|
1257
|
+
results
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1091
1260
|
const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
1092
1261
|
if (!runnerInterval) {
|
|
1093
1262
|
runnerInterval = setInterval(async () => {
|
|
@@ -1099,7 +1268,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1099
1268
|
for (const [id, batch] of pendingBatches.entries()) {
|
|
1100
1269
|
if (batch.status === "queued_offpeak" && !isBusinessHours) {
|
|
1101
1270
|
strapi2.log.info(`[bulk-updater] Executing off-peak queued batch: ${id}`);
|
|
1102
|
-
const result = await executeBatchInternal(strapi2, batch.payload, batch.createdBy, id);
|
|
1271
|
+
const result = batch.payload?.action === "publish" ? await executePublishBatchInternal(strapi2, batch.payload, batch.createdBy, id) : await executeBatchInternal(strapi2, batch.payload, batch.createdBy, id);
|
|
1103
1272
|
batch.status = "executed";
|
|
1104
1273
|
batch.executionResult = result;
|
|
1105
1274
|
}
|
|
@@ -1196,6 +1365,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1196
1365
|
uid,
|
|
1197
1366
|
kind: contentType.kind,
|
|
1198
1367
|
isSingleType,
|
|
1368
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1199
1369
|
singularName: contentType.info?.singularName || uid,
|
|
1200
1370
|
pluralName: contentType.info?.pluralName || uid,
|
|
1201
1371
|
displayName: contentType.info?.displayName || uid,
|
|
@@ -1377,6 +1547,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1377
1547
|
uid,
|
|
1378
1548
|
displayName: contentType.info?.displayName || uid,
|
|
1379
1549
|
isSingleType,
|
|
1550
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1380
1551
|
entries: [],
|
|
1381
1552
|
pagination: {
|
|
1382
1553
|
page: 1,
|
|
@@ -1390,10 +1561,12 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1390
1561
|
}
|
|
1391
1562
|
let condition = void 0;
|
|
1392
1563
|
const q = (filterQuery || "").trim();
|
|
1564
|
+
const targetAttrSchema = isNestedAttr ? strapi2.components[attrs[parentKey]?.component]?.attributes?.[childKey] : attrs[attribute];
|
|
1565
|
+
const isStringLike = ["string", "text", "email", "richtext", "uid"].includes(targetAttrSchema?.type);
|
|
1393
1566
|
if (normOp === "empty") {
|
|
1394
|
-
condition = { $or: [{ $null: true }, { $eq: "" }] };
|
|
1567
|
+
condition = isStringLike ? { $or: [{ $null: true }, { $eq: "" }] } : { $null: true };
|
|
1395
1568
|
} else if (normOp === "notempty") {
|
|
1396
|
-
condition = { $and: [{ $notNull: true }, { $ne: "" }] };
|
|
1569
|
+
condition = isStringLike ? { $and: [{ $notNull: true }, { $ne: "" }] } : { $notNull: true };
|
|
1397
1570
|
} else if (q !== "") {
|
|
1398
1571
|
switch (normOp) {
|
|
1399
1572
|
case "equals":
|
|
@@ -1422,12 +1595,12 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1422
1595
|
[childKey]: condition
|
|
1423
1596
|
};
|
|
1424
1597
|
} else {
|
|
1425
|
-
if (normOp === "empty") {
|
|
1598
|
+
if (normOp === "empty" && isStringLike) {
|
|
1426
1599
|
filters2.$or = [
|
|
1427
1600
|
{ [attribute]: { $null: true } },
|
|
1428
1601
|
{ [attribute]: { $eq: "" } }
|
|
1429
1602
|
];
|
|
1430
|
-
} else if (normOp === "notempty") {
|
|
1603
|
+
} else if (normOp === "notempty" && isStringLike) {
|
|
1431
1604
|
filters2[attribute] = { $notNull: true, $ne: "" };
|
|
1432
1605
|
} else {
|
|
1433
1606
|
filters2[attribute] = condition;
|
|
@@ -1466,6 +1639,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1466
1639
|
uid,
|
|
1467
1640
|
displayName: contentType.info?.displayName || uid,
|
|
1468
1641
|
isSingleType: true,
|
|
1642
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1469
1643
|
entries: singleDoc ? [singleDoc] : [],
|
|
1470
1644
|
pagination: {
|
|
1471
1645
|
page: 1,
|
|
@@ -1509,6 +1683,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1509
1683
|
uid,
|
|
1510
1684
|
displayName: contentType.info?.displayName || uid,
|
|
1511
1685
|
isSingleType: false,
|
|
1686
|
+
draftAndPublish: Boolean(contentType.options?.draftAndPublish),
|
|
1512
1687
|
entries: (entries || []).map((entry) => ({
|
|
1513
1688
|
id: entry.id,
|
|
1514
1689
|
documentId: entry.documentId,
|
|
@@ -2009,6 +2184,199 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
2009
2184
|
currentUser
|
|
2010
2185
|
);
|
|
2011
2186
|
},
|
|
2187
|
+
/**
|
|
2188
|
+
* Bulk Publish selected entries or collections
|
|
2189
|
+
*/
|
|
2190
|
+
async batchPublish({
|
|
2191
|
+
selectedEntries = [],
|
|
2192
|
+
selectedCollections = [],
|
|
2193
|
+
executionMode = "immediate",
|
|
2194
|
+
makerNotes = "",
|
|
2195
|
+
forceImmediate = false
|
|
2196
|
+
}, currentUser) {
|
|
2197
|
+
const executionConfig = getExecutionWindowConfig(strapi2);
|
|
2198
|
+
const { isBusinessHours, policyMessage } = checkBusinessHours(executionConfig);
|
|
2199
|
+
if (executionMode === "maker_checker") {
|
|
2200
|
+
const summary = await computeTargetsSummary(strapi2, { selectedCollections, selectedEntries });
|
|
2201
|
+
if (summary.totalTargets === 0) {
|
|
2202
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
2203
|
+
}
|
|
2204
|
+
const batchId = `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2205
|
+
const batch = {
|
|
2206
|
+
id: batchId,
|
|
2207
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2208
|
+
createdBy: currentUser ? {
|
|
2209
|
+
id: currentUser.id,
|
|
2210
|
+
email: currentUser.email,
|
|
2211
|
+
firstname: currentUser.firstname,
|
|
2212
|
+
lastname: currentUser.lastname,
|
|
2213
|
+
username: currentUser.username
|
|
2214
|
+
} : { email: "admin@system.local" },
|
|
2215
|
+
payload: { action: "publish", attribute: "(publish)", value: "published", selectedEntries, selectedCollections, publishOnApproval: true },
|
|
2216
|
+
summary: {
|
|
2217
|
+
attribute: "(publish)",
|
|
2218
|
+
value: "published",
|
|
2219
|
+
totalTargets: summary.totalTargets,
|
|
2220
|
+
collectionBreakdown: summary.collectionBreakdown,
|
|
2221
|
+
publishOnApproval: true
|
|
2222
|
+
},
|
|
2223
|
+
status: "pending_approval",
|
|
2224
|
+
executionMode: "maker_checker",
|
|
2225
|
+
makerNotes
|
|
2226
|
+
};
|
|
2227
|
+
pendingBatches.set(batchId, batch);
|
|
2228
|
+
batchJobsMap.set(batchId, {
|
|
2229
|
+
id: batchId,
|
|
2230
|
+
createdAt: batch.createdAt,
|
|
2231
|
+
createdBy: batch.createdBy,
|
|
2232
|
+
status: "pending_approval",
|
|
2233
|
+
executionMode: "maker_checker",
|
|
2234
|
+
attribute: "(publish)",
|
|
2235
|
+
value: "published",
|
|
2236
|
+
totalTargets: summary.totalTargets,
|
|
2237
|
+
processedCount: 0,
|
|
2238
|
+
updatedCount: 0,
|
|
2239
|
+
skippedCount: 0,
|
|
2240
|
+
failedCount: 0,
|
|
2241
|
+
isLive: false,
|
|
2242
|
+
publishOnApproval: true,
|
|
2243
|
+
makerNotes,
|
|
2244
|
+
results: []
|
|
2245
|
+
});
|
|
2246
|
+
return {
|
|
2247
|
+
success: true,
|
|
2248
|
+
pending: true,
|
|
2249
|
+
batchId,
|
|
2250
|
+
status: "pending_approval",
|
|
2251
|
+
message: "Bulk publish batch submitted for Checker authorization (4-Eyes Maker-Checker Workflow).",
|
|
2252
|
+
batch
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
if (executionMode === "queue_offpeak") {
|
|
2256
|
+
const summary = await computeTargetsSummary(strapi2, { selectedCollections, selectedEntries });
|
|
2257
|
+
if (summary.totalTargets === 0) {
|
|
2258
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
2259
|
+
}
|
|
2260
|
+
const batchId = `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2261
|
+
const batch = {
|
|
2262
|
+
id: batchId,
|
|
2263
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2264
|
+
createdBy: currentUser ? {
|
|
2265
|
+
id: currentUser.id,
|
|
2266
|
+
email: currentUser.email,
|
|
2267
|
+
firstname: currentUser.firstname,
|
|
2268
|
+
lastname: currentUser.lastname,
|
|
2269
|
+
username: currentUser.username
|
|
2270
|
+
} : { email: "admin@system.local" },
|
|
2271
|
+
payload: { action: "publish", attribute: "(publish)", value: "published", selectedEntries, selectedCollections, publishOnApproval: true },
|
|
2272
|
+
summary: {
|
|
2273
|
+
attribute: "(publish)",
|
|
2274
|
+
value: "published",
|
|
2275
|
+
totalTargets: summary.totalTargets,
|
|
2276
|
+
collectionBreakdown: summary.collectionBreakdown,
|
|
2277
|
+
publishOnApproval: true
|
|
2278
|
+
},
|
|
2279
|
+
status: "queued_offpeak",
|
|
2280
|
+
executionMode: "queue_offpeak",
|
|
2281
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2282
|
+
makerNotes
|
|
2283
|
+
};
|
|
2284
|
+
pendingBatches.set(batchId, batch);
|
|
2285
|
+
batchJobsMap.set(batchId, {
|
|
2286
|
+
id: batchId,
|
|
2287
|
+
createdAt: batch.createdAt,
|
|
2288
|
+
createdBy: batch.createdBy,
|
|
2289
|
+
status: "queued_offpeak",
|
|
2290
|
+
executionMode: "queue_offpeak",
|
|
2291
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2292
|
+
attribute: "(publish)",
|
|
2293
|
+
value: "published",
|
|
2294
|
+
totalTargets: summary.totalTargets,
|
|
2295
|
+
processedCount: 0,
|
|
2296
|
+
updatedCount: 0,
|
|
2297
|
+
skippedCount: 0,
|
|
2298
|
+
failedCount: 0,
|
|
2299
|
+
isLive: false,
|
|
2300
|
+
publishOnApproval: true,
|
|
2301
|
+
makerNotes,
|
|
2302
|
+
results: []
|
|
2303
|
+
});
|
|
2304
|
+
return {
|
|
2305
|
+
success: true,
|
|
2306
|
+
pending: true,
|
|
2307
|
+
batchId,
|
|
2308
|
+
status: "queued_offpeak",
|
|
2309
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2310
|
+
message: `Bulk publish batch queued for server off-peak maintenance window (${executionConfig.offPeakStartTime}).`,
|
|
2311
|
+
batch
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
if (executionConfig.enabled && executionConfig.autoQueueDuringBusinessHours && isBusinessHours && !forceImmediate) {
|
|
2315
|
+
const summary = await computeTargetsSummary(strapi2, { selectedCollections, selectedEntries });
|
|
2316
|
+
if (summary.totalTargets === 0) {
|
|
2317
|
+
throw new Error("No collections or entries were selected to publish.");
|
|
2318
|
+
}
|
|
2319
|
+
const batchId = `batch_pub_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2320
|
+
const batch = {
|
|
2321
|
+
id: batchId,
|
|
2322
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2323
|
+
createdBy: currentUser ? {
|
|
2324
|
+
id: currentUser.id,
|
|
2325
|
+
email: currentUser.email,
|
|
2326
|
+
firstname: currentUser.firstname,
|
|
2327
|
+
lastname: currentUser.lastname,
|
|
2328
|
+
username: currentUser.username
|
|
2329
|
+
} : { email: "admin@system.local" },
|
|
2330
|
+
payload: { action: "publish", attribute: "(publish)", value: "published", selectedEntries, selectedCollections, publishOnApproval: true },
|
|
2331
|
+
summary: {
|
|
2332
|
+
attribute: "(publish)",
|
|
2333
|
+
value: "published",
|
|
2334
|
+
totalTargets: summary.totalTargets,
|
|
2335
|
+
collectionBreakdown: summary.collectionBreakdown,
|
|
2336
|
+
publishOnApproval: true
|
|
2337
|
+
},
|
|
2338
|
+
status: "queued_offpeak",
|
|
2339
|
+
executionMode: "queue_offpeak",
|
|
2340
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2341
|
+
makerNotes: "Automatically queued due to peak business hours restriction."
|
|
2342
|
+
};
|
|
2343
|
+
pendingBatches.set(batchId, batch);
|
|
2344
|
+
batchJobsMap.set(batchId, {
|
|
2345
|
+
id: batchId,
|
|
2346
|
+
createdAt: batch.createdAt,
|
|
2347
|
+
createdBy: batch.createdBy,
|
|
2348
|
+
status: "queued_offpeak",
|
|
2349
|
+
executionMode: "queue_offpeak",
|
|
2350
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2351
|
+
attribute: "(publish)",
|
|
2352
|
+
value: "published",
|
|
2353
|
+
totalTargets: summary.totalTargets,
|
|
2354
|
+
processedCount: 0,
|
|
2355
|
+
updatedCount: 0,
|
|
2356
|
+
skippedCount: 0,
|
|
2357
|
+
failedCount: 0,
|
|
2358
|
+
isLive: false,
|
|
2359
|
+
publishOnApproval: true,
|
|
2360
|
+
policyMessage,
|
|
2361
|
+
makerNotes: "Automatically queued due to peak business hours restriction.",
|
|
2362
|
+
results: []
|
|
2363
|
+
});
|
|
2364
|
+
return {
|
|
2365
|
+
success: true,
|
|
2366
|
+
pending: true,
|
|
2367
|
+
batchId,
|
|
2368
|
+
status: "queued_offpeak",
|
|
2369
|
+
scheduledFor: executionConfig.offPeakStartTime,
|
|
2370
|
+
message: policyMessage,
|
|
2371
|
+
batch
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
return await executePublishBatchInternal(
|
|
2375
|
+
strapi2,
|
|
2376
|
+
{ selectedEntries, selectedCollections },
|
|
2377
|
+
currentUser
|
|
2378
|
+
);
|
|
2379
|
+
},
|
|
2012
2380
|
/**
|
|
2013
2381
|
* Get Pending & Queued Batches
|
|
2014
2382
|
*/
|
|
@@ -2052,7 +2420,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
2052
2420
|
const { isBusinessHours } = checkBusinessHours(config);
|
|
2053
2421
|
if (options.executeImmediately || !isBusinessHours) {
|
|
2054
2422
|
batch.status = "approved";
|
|
2055
|
-
const result = await executeBatchInternal(strapi2, batch.payload, checkerUser, batch.id);
|
|
2423
|
+
const result = batch.payload?.action === "publish" ? await executePublishBatchInternal(strapi2, batch.payload, checkerUser, batch.id) : await executeBatchInternal(strapi2, batch.payload, checkerUser, batch.id);
|
|
2056
2424
|
batch.status = "executed";
|
|
2057
2425
|
batch.executionResult = result;
|
|
2058
2426
|
return {
|
|
@@ -2113,7 +2481,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
2113
2481
|
if (batch.status === "executed") {
|
|
2114
2482
|
throw new Error(`Batch ${batchId} has already been executed.`);
|
|
2115
2483
|
}
|
|
2116
|
-
const result = await executeBatchInternal(strapi2, batch.payload, currentUser, batch.id);
|
|
2484
|
+
const result = batch.payload?.action === "publish" ? await executePublishBatchInternal(strapi2, batch.payload, currentUser, batch.id) : await executeBatchInternal(strapi2, batch.payload, currentUser, batch.id);
|
|
2117
2485
|
batch.status = "executed";
|
|
2118
2486
|
batch.executionResult = result;
|
|
2119
2487
|
return {
|