strapi-plugin-bulk-updater 1.3.3 → 1.3.6
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-C2lw4D0D.js → BulkUpdater-CXDs0Dws.js} +181 -142
- package/dist/_chunks/BulkUpdater-CXDs0Dws.js.map +1 -0
- package/dist/_chunks/{BulkUpdater-CgsqzdyX.mjs → BulkUpdater-D812YfOE.mjs} +182 -143
- package/dist/_chunks/BulkUpdater-D812YfOE.mjs.map +1 -0
- package/dist/admin/index.js +43 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +42 -2
- package/dist/admin/index.mjs.map +1 -1
- package/dist/server/index.js +405 -62
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +405 -62
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/_chunks/BulkUpdater-C2lw4D0D.js.map +0 -1
- package/dist/_chunks/BulkUpdater-CgsqzdyX.mjs.map +0 -1
package/dist/server/index.mjs
CHANGED
|
@@ -675,6 +675,149 @@ const csvController = ({ strapi: strapi2 }) => ({
|
|
|
675
675
|
}
|
|
676
676
|
}
|
|
677
677
|
});
|
|
678
|
+
const FIELDS_TO_IGNORE = [
|
|
679
|
+
"createdAt",
|
|
680
|
+
"updatedAt",
|
|
681
|
+
"publishedAt",
|
|
682
|
+
"createdBy",
|
|
683
|
+
"updatedBy",
|
|
684
|
+
"strapi_stage",
|
|
685
|
+
"strapi_assignee"
|
|
686
|
+
];
|
|
687
|
+
function buildHistoryPopulate(attributes, allComponents, depth2 = 0) {
|
|
688
|
+
if (depth2 > 5) return void 0;
|
|
689
|
+
const populate2 = {};
|
|
690
|
+
for (const [key, def] of Object.entries(attributes || {})) {
|
|
691
|
+
if (def.type === "component" && def.component) {
|
|
692
|
+
const comp = allComponents[def.component];
|
|
693
|
+
if (comp?.attributes) {
|
|
694
|
+
const subPopulate = buildHistoryPopulate(comp.attributes, allComponents, depth2 + 1);
|
|
695
|
+
if (subPopulate && Object.keys(subPopulate).length > 0) {
|
|
696
|
+
populate2[key] = {
|
|
697
|
+
populate: subPopulate
|
|
698
|
+
};
|
|
699
|
+
} else {
|
|
700
|
+
populate2[key] = true;
|
|
701
|
+
}
|
|
702
|
+
} else {
|
|
703
|
+
populate2[key] = true;
|
|
704
|
+
}
|
|
705
|
+
} else if (def.type === "dynamiczone") {
|
|
706
|
+
populate2[key] = true;
|
|
707
|
+
} else if (def.type === "relation" || def.type === "media") {
|
|
708
|
+
populate2[key] = true;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return Object.keys(populate2).length > 0 ? populate2 : void 0;
|
|
712
|
+
}
|
|
713
|
+
let cachedAdminUserId = null;
|
|
714
|
+
async function recordContentHistoryVersion(strapi2, options) {
|
|
715
|
+
const { uid, documentId, userId, statusOverride } = options;
|
|
716
|
+
if (!uid || !uid.startsWith("api::") || !documentId) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
try {
|
|
720
|
+
const historyQuery = strapi2.db?.query?.("plugin::content-manager.history-version");
|
|
721
|
+
if (!historyQuery) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const model = strapi2.getModel?.(uid);
|
|
725
|
+
if (!model) {
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
let entry = null;
|
|
729
|
+
try {
|
|
730
|
+
entry = await strapi2.db.query(uid).findOne({
|
|
731
|
+
where: { documentId },
|
|
732
|
+
populate: true
|
|
733
|
+
});
|
|
734
|
+
} catch {
|
|
735
|
+
try {
|
|
736
|
+
const populateOption = buildHistoryPopulate(model.attributes || {}, strapi2.components || {});
|
|
737
|
+
entry = await strapi2.documents(uid).findOne({
|
|
738
|
+
documentId,
|
|
739
|
+
...populateOption ? { populate: populateOption } : {}
|
|
740
|
+
});
|
|
741
|
+
} catch {
|
|
742
|
+
entry = null;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (!entry) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const attributesSchema = model.attributes || {};
|
|
749
|
+
const sanitizedSchema = Object.fromEntries(
|
|
750
|
+
Object.entries(attributesSchema).filter(([k]) => !FIELDS_TO_IGNORE.includes(k))
|
|
751
|
+
);
|
|
752
|
+
const sanitizedData = Object.fromEntries(
|
|
753
|
+
Object.entries(entry).filter(([k]) => !FIELDS_TO_IGNORE.includes(k) && k !== "id")
|
|
754
|
+
);
|
|
755
|
+
let status2 = statusOverride || "published";
|
|
756
|
+
if (!statusOverride) {
|
|
757
|
+
const hasDraftAndPublish = Boolean(model.options?.draftAndPublish);
|
|
758
|
+
if (hasDraftAndPublish) {
|
|
759
|
+
try {
|
|
760
|
+
const docMetaService = strapi2.plugin("content-manager")?.service("document-metadata");
|
|
761
|
+
if (docMetaService) {
|
|
762
|
+
const meta = await docMetaService.getMetadata(uid, entry);
|
|
763
|
+
status2 = docMetaService.getStatus(entry, meta.availableStatus);
|
|
764
|
+
} else {
|
|
765
|
+
status2 = entry.publishedAt ? "published" : "draft";
|
|
766
|
+
}
|
|
767
|
+
} catch {
|
|
768
|
+
status2 = entry.publishedAt ? "published" : "draft";
|
|
769
|
+
}
|
|
770
|
+
} else {
|
|
771
|
+
status2 = "published";
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
let authorId = userId;
|
|
775
|
+
if (!authorId) {
|
|
776
|
+
authorId = strapi2.requestContext?.get?.()?.state?.user?.id || null;
|
|
777
|
+
}
|
|
778
|
+
let numericUserId = authorId ? Number(authorId) : null;
|
|
779
|
+
if (!numericUserId || isNaN(numericUserId)) {
|
|
780
|
+
if (cachedAdminUserId) {
|
|
781
|
+
numericUserId = cachedAdminUserId;
|
|
782
|
+
} else {
|
|
783
|
+
try {
|
|
784
|
+
const firstAdmin = await strapi2.db?.query?.("admin::user")?.findOne?.({ select: ["id"] });
|
|
785
|
+
if (firstAdmin?.id) {
|
|
786
|
+
cachedAdminUserId = Number(firstAdmin.id);
|
|
787
|
+
numericUserId = cachedAdminUserId;
|
|
788
|
+
}
|
|
789
|
+
} catch {
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
await historyQuery.create({
|
|
794
|
+
data: {
|
|
795
|
+
contentType: uid,
|
|
796
|
+
relatedDocumentId: documentId,
|
|
797
|
+
locale: entry.locale || null,
|
|
798
|
+
status: status2,
|
|
799
|
+
data: sanitizedData,
|
|
800
|
+
schema: sanitizedSchema,
|
|
801
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
802
|
+
...numericUserId && !isNaN(numericUserId) ? { createdBy: numericUserId } : {}
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
} catch (err) {
|
|
806
|
+
strapi2.log?.warn?.(`[bulk-updater] Non-blocking Content History notice for ${uid}/${documentId}: ${err?.message}`);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
async function recordContentHistoryVersionsBatch(strapi2, items) {
|
|
810
|
+
if (!items || items.length === 0) return;
|
|
811
|
+
const BATCH_SIZE = 10;
|
|
812
|
+
for (let i = 0; i < items.length; i += BATCH_SIZE) {
|
|
813
|
+
const slice = items.slice(i, i + BATCH_SIZE);
|
|
814
|
+
await Promise.all(slice.map((item) => recordContentHistoryVersion(strapi2, item)));
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
const contentHistoryService = {
|
|
818
|
+
recordContentHistoryVersion,
|
|
819
|
+
recordContentHistoryVersionsBatch
|
|
820
|
+
};
|
|
678
821
|
const queryCache = /* @__PURE__ */ new Map();
|
|
679
822
|
const modelsCache = /* @__PURE__ */ new Map();
|
|
680
823
|
const MAX_QUERY_CACHE_SIZE = 500;
|
|
@@ -1051,6 +1194,12 @@ async function executeBatchInternal(strapi2, {
|
|
|
1051
1194
|
}
|
|
1052
1195
|
}
|
|
1053
1196
|
invalidateCollectionCache(target.uid);
|
|
1197
|
+
await recordContentHistoryVersion(strapi2, {
|
|
1198
|
+
uid: target.uid,
|
|
1199
|
+
documentId: target.documentId,
|
|
1200
|
+
userId: currentUser?.id,
|
|
1201
|
+
statusOverride: publishOnApproval && isDraftAndPublishComp ? "published" : void 0
|
|
1202
|
+
});
|
|
1054
1203
|
return {
|
|
1055
1204
|
uid: target.uid,
|
|
1056
1205
|
collectionName: displayName,
|
|
@@ -1136,6 +1285,12 @@ async function executeBatchInternal(strapi2, {
|
|
|
1136
1285
|
if (attrDef.target) {
|
|
1137
1286
|
invalidateCollectionCache(attrDef.target);
|
|
1138
1287
|
}
|
|
1288
|
+
await recordContentHistoryVersion(strapi2, {
|
|
1289
|
+
uid: target.uid,
|
|
1290
|
+
documentId: target.documentId,
|
|
1291
|
+
userId: currentUser?.id,
|
|
1292
|
+
statusOverride: publishOnApproval && isDraftAndPublishRel ? "published" : void 0
|
|
1293
|
+
});
|
|
1139
1294
|
return {
|
|
1140
1295
|
uid: target.uid,
|
|
1141
1296
|
collectionName: displayName,
|
|
@@ -1169,6 +1324,12 @@ async function executeBatchInternal(strapi2, {
|
|
|
1169
1324
|
strapi2.log.warn(`[bulk-updater] Failed to auto-publish ${target.uid}/${target.documentId}:`, publishErr);
|
|
1170
1325
|
}
|
|
1171
1326
|
}
|
|
1327
|
+
await recordContentHistoryVersion(strapi2, {
|
|
1328
|
+
uid: target.uid,
|
|
1329
|
+
documentId: target.documentId,
|
|
1330
|
+
userId: currentUser?.id,
|
|
1331
|
+
statusOverride: publishOnApproval && isDraftAndPublishScalar ? "published" : void 0
|
|
1332
|
+
});
|
|
1172
1333
|
return {
|
|
1173
1334
|
uid: target.uid,
|
|
1174
1335
|
collectionName: displayName,
|
|
@@ -1339,6 +1500,12 @@ async function executePublishBatchInternal(strapi2, {
|
|
|
1339
1500
|
documentId: target.documentId
|
|
1340
1501
|
});
|
|
1341
1502
|
invalidateCollectionCache(target.uid);
|
|
1503
|
+
await recordContentHistoryVersion(strapi2, {
|
|
1504
|
+
uid: target.uid,
|
|
1505
|
+
documentId: target.documentId,
|
|
1506
|
+
userId: currentUser?.id,
|
|
1507
|
+
statusOverride: "published"
|
|
1508
|
+
});
|
|
1342
1509
|
return {
|
|
1343
1510
|
uid: target.uid,
|
|
1344
1511
|
collectionName: displayName,
|
|
@@ -3194,7 +3361,7 @@ const auditService = ({ strapi: strapi2 }) => ({
|
|
|
3194
3361
|
/**
|
|
3195
3362
|
* Helper to revert diff items back to original values
|
|
3196
3363
|
*/
|
|
3197
|
-
async revertDiffItems(diffs) {
|
|
3364
|
+
async revertDiffItems(diffs, userId) {
|
|
3198
3365
|
let revertedCount = 0;
|
|
3199
3366
|
const rollbackDetails = [];
|
|
3200
3367
|
for (const item of diffs) {
|
|
@@ -3252,6 +3419,15 @@ const auditService = ({ strapi: strapi2 }) => ({
|
|
|
3252
3419
|
} catch {
|
|
3253
3420
|
}
|
|
3254
3421
|
}
|
|
3422
|
+
try {
|
|
3423
|
+
await recordContentHistoryVersion(strapi2, {
|
|
3424
|
+
uid: item.uid,
|
|
3425
|
+
documentId: item.documentId,
|
|
3426
|
+
userId,
|
|
3427
|
+
statusOverride: ct?.options?.draftAndPublish ? "published" : void 0
|
|
3428
|
+
});
|
|
3429
|
+
} catch {
|
|
3430
|
+
}
|
|
3255
3431
|
try {
|
|
3256
3432
|
const bulkService = strapi2.plugin("bulk-updater").service("bulkUpdater");
|
|
3257
3433
|
if (bulkService?.invalidateCache) {
|
|
@@ -3302,7 +3478,7 @@ const auditService = ({ strapi: strapi2 }) => ({
|
|
|
3302
3478
|
throw new Error(`Batch "${batchId}" has already been rolled back.`);
|
|
3303
3479
|
}
|
|
3304
3480
|
const diffs2 = Array.isArray(record2.diffs) ? record2.diffs : [];
|
|
3305
|
-
const { revertedCount: revertedCount2, rollbackDetails: rollbackDetails2 } = await this.revertDiffItems(diffs2);
|
|
3481
|
+
const { revertedCount: revertedCount2, rollbackDetails: rollbackDetails2 } = await this.revertDiffItems(diffs2, currentUser?.id);
|
|
3306
3482
|
record2.isRolledBack = true;
|
|
3307
3483
|
record2.rolledBackAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3308
3484
|
record2.rolledBackBy = currentUser?.email || "Admin";
|
|
@@ -3350,7 +3526,7 @@ const auditService = ({ strapi: strapi2 }) => ({
|
|
|
3350
3526
|
throw new Error(`Batch "${batchId}" has already been rolled back.`);
|
|
3351
3527
|
}
|
|
3352
3528
|
const diffs = typeof record[f.diffs] === "string" ? JSON.parse(record[f.diffs]) : record[f.diffs] || [];
|
|
3353
|
-
const { revertedCount, rollbackDetails } = await this.revertDiffItems(diffs);
|
|
3529
|
+
const { revertedCount, rollbackDetails } = await this.revertDiffItems(diffs, currentUser?.id);
|
|
3354
3530
|
const updateData = {};
|
|
3355
3531
|
if (f.isRolledBack) updateData[f.isRolledBack] = true;
|
|
3356
3532
|
if (f.rolledBackAt) updateData[f.rolledBackAt] = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3626,77 +3802,93 @@ function escapeCsvValue(val) {
|
|
|
3626
3802
|
}
|
|
3627
3803
|
return str2;
|
|
3628
3804
|
}
|
|
3629
|
-
function
|
|
3805
|
+
function parseCsvRows(csvText) {
|
|
3630
3806
|
if (!csvText) return [];
|
|
3631
|
-
let
|
|
3632
|
-
if (
|
|
3633
|
-
|
|
3807
|
+
let text = csvText;
|
|
3808
|
+
if (text.charCodeAt(0) === 65279) {
|
|
3809
|
+
text = text.slice(1);
|
|
3634
3810
|
}
|
|
3635
|
-
const
|
|
3636
|
-
let
|
|
3811
|
+
const rows = [];
|
|
3812
|
+
let currentRow = [];
|
|
3813
|
+
let currentCell = "";
|
|
3637
3814
|
let inQuotes = false;
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
const
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3815
|
+
let cellIsQuoted = false;
|
|
3816
|
+
for (let i = 0; i < text.length; i++) {
|
|
3817
|
+
const char = text[i];
|
|
3818
|
+
const nextChar = text[i + 1];
|
|
3819
|
+
if (inQuotes) {
|
|
3820
|
+
if (char === '"') {
|
|
3821
|
+
if (nextChar === '"') {
|
|
3822
|
+
currentCell += '"';
|
|
3823
|
+
i++;
|
|
3824
|
+
} else {
|
|
3825
|
+
inQuotes = false;
|
|
3826
|
+
}
|
|
3645
3827
|
} else {
|
|
3646
|
-
|
|
3647
|
-
}
|
|
3648
|
-
} else if ((char === "\r" || char === "\n") && !inQuotes) {
|
|
3649
|
-
if (char === "\r" && nextChar === "\n") {
|
|
3650
|
-
i++;
|
|
3828
|
+
currentCell += char;
|
|
3651
3829
|
}
|
|
3652
|
-
if (current.trim().length > 0) {
|
|
3653
|
-
lines.push(current);
|
|
3654
|
-
}
|
|
3655
|
-
current = "";
|
|
3656
3830
|
} else {
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
let inQ = false;
|
|
3668
|
-
for (let i = 0; i < line.length; i++) {
|
|
3669
|
-
const c = line[i];
|
|
3670
|
-
const nc = line[i + 1];
|
|
3671
|
-
if (c === '"') {
|
|
3672
|
-
if (inQ && nc === '"') {
|
|
3673
|
-
field += '"';
|
|
3831
|
+
if (char === '"' && !cellIsQuoted && currentCell.trim() === "") {
|
|
3832
|
+
inQuotes = true;
|
|
3833
|
+
cellIsQuoted = true;
|
|
3834
|
+
currentCell = "";
|
|
3835
|
+
} else if (char === ",") {
|
|
3836
|
+
currentRow.push(cellIsQuoted ? currentCell : currentCell.trim());
|
|
3837
|
+
currentCell = "";
|
|
3838
|
+
cellIsQuoted = false;
|
|
3839
|
+
} else if (char === "\r") {
|
|
3840
|
+
if (nextChar === "\n") {
|
|
3674
3841
|
i++;
|
|
3675
|
-
} else {
|
|
3676
|
-
inQ = !inQ;
|
|
3677
3842
|
}
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3843
|
+
currentRow.push(cellIsQuoted ? currentCell : currentCell.trim());
|
|
3844
|
+
if (currentRow.length > 1 || currentRow.length === 1 && currentRow[0] !== "") {
|
|
3845
|
+
rows.push(currentRow);
|
|
3846
|
+
}
|
|
3847
|
+
currentRow = [];
|
|
3848
|
+
currentCell = "";
|
|
3849
|
+
cellIsQuoted = false;
|
|
3850
|
+
} else if (char === "\n") {
|
|
3851
|
+
currentRow.push(cellIsQuoted ? currentCell : currentCell.trim());
|
|
3852
|
+
if (currentRow.length > 1 || currentRow.length === 1 && currentRow[0] !== "") {
|
|
3853
|
+
rows.push(currentRow);
|
|
3854
|
+
}
|
|
3855
|
+
currentRow = [];
|
|
3856
|
+
currentCell = "";
|
|
3857
|
+
cellIsQuoted = false;
|
|
3681
3858
|
} else {
|
|
3682
|
-
|
|
3859
|
+
if (!(cellIsQuoted && !inQuotes && (char === " " || char === " "))) {
|
|
3860
|
+
currentCell += char;
|
|
3861
|
+
}
|
|
3683
3862
|
}
|
|
3684
3863
|
}
|
|
3685
|
-
fields2.push(field);
|
|
3686
|
-
return fields2.map((f) => f.trim());
|
|
3687
3864
|
}
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
headers.forEach((h, index2) => {
|
|
3694
|
-
rowObj[h] = values[index2] !== void 0 ? values[index2] : "";
|
|
3695
|
-
});
|
|
3696
|
-
rows.push(rowObj);
|
|
3865
|
+
if (currentCell !== "" || cellIsQuoted || currentRow.length > 0) {
|
|
3866
|
+
currentRow.push(cellIsQuoted ? currentCell : currentCell.trim());
|
|
3867
|
+
if (currentRow.length > 1 || currentRow.length === 1 && currentRow[0] !== "") {
|
|
3868
|
+
rows.push(currentRow);
|
|
3869
|
+
}
|
|
3697
3870
|
}
|
|
3698
3871
|
return rows;
|
|
3699
3872
|
}
|
|
3873
|
+
function parseCsv(csvText) {
|
|
3874
|
+
const rows = parseCsvRows(csvText);
|
|
3875
|
+
if (rows.length < 2) return [];
|
|
3876
|
+
const headers = rows[0].map((h) => h.trim());
|
|
3877
|
+
const records = [];
|
|
3878
|
+
for (let i = 1; i < rows.length; i++) {
|
|
3879
|
+
const row = rows[i];
|
|
3880
|
+
const record = {};
|
|
3881
|
+
headers.forEach((h, idx) => {
|
|
3882
|
+
let val = row[idx] !== void 0 ? row[idx] : "";
|
|
3883
|
+
if (typeof val === "string" && /^'[=+@-]/.test(val)) {
|
|
3884
|
+
val = val.substring(1);
|
|
3885
|
+
}
|
|
3886
|
+
record[h] = val;
|
|
3887
|
+
});
|
|
3888
|
+
records.push(record);
|
|
3889
|
+
}
|
|
3890
|
+
return records;
|
|
3891
|
+
}
|
|
3700
3892
|
function discoverExportFields(ct, allComponents, maxDepth = 4) {
|
|
3701
3893
|
const fields2 = [{ key: "documentId", label: "documentId", type: "string" }];
|
|
3702
3894
|
const excluded = ["createdBy", "updatedBy", "localizations"];
|
|
@@ -4190,6 +4382,15 @@ const csvService = ({ strapi: strapi2 }) => ({
|
|
|
4190
4382
|
strapi2.log.warn(`[bulk-updater] Auto-publish failed for ${docId}:`, pubErr);
|
|
4191
4383
|
}
|
|
4192
4384
|
}
|
|
4385
|
+
try {
|
|
4386
|
+
await recordContentHistoryVersion(strapi2, {
|
|
4387
|
+
uid,
|
|
4388
|
+
documentId: docId,
|
|
4389
|
+
userId: user?.id,
|
|
4390
|
+
statusOverride: publish && ct.options?.draftAndPublish ? "published" : void 0
|
|
4391
|
+
});
|
|
4392
|
+
} catch {
|
|
4393
|
+
}
|
|
4193
4394
|
stats.updated++;
|
|
4194
4395
|
stats.diffs.push({
|
|
4195
4396
|
uid,
|
|
@@ -4225,6 +4426,15 @@ const csvService = ({ strapi: strapi2 }) => ({
|
|
|
4225
4426
|
strapi2.log.warn(`[bulk-updater] Auto-publish failed for ${docId}:`, pubErr);
|
|
4226
4427
|
}
|
|
4227
4428
|
}
|
|
4429
|
+
try {
|
|
4430
|
+
await recordContentHistoryVersion(strapi2, {
|
|
4431
|
+
uid,
|
|
4432
|
+
documentId: docId,
|
|
4433
|
+
userId: user?.id,
|
|
4434
|
+
statusOverride: publish && ct.options?.draftAndPublish ? "published" : void 0
|
|
4435
|
+
});
|
|
4436
|
+
} catch {
|
|
4437
|
+
}
|
|
4228
4438
|
stats.updated++;
|
|
4229
4439
|
stats.diffs.push({
|
|
4230
4440
|
uid,
|
|
@@ -4251,6 +4461,15 @@ const csvService = ({ strapi: strapi2 }) => ({
|
|
|
4251
4461
|
strapi2.log.warn(`[bulk-updater] Auto-publish failed for ${newDocId}:`, pubErr);
|
|
4252
4462
|
}
|
|
4253
4463
|
}
|
|
4464
|
+
try {
|
|
4465
|
+
await recordContentHistoryVersion(strapi2, {
|
|
4466
|
+
uid,
|
|
4467
|
+
documentId: newDocId,
|
|
4468
|
+
userId: user?.id,
|
|
4469
|
+
statusOverride: publish && ct.options?.draftAndPublish ? "published" : void 0
|
|
4470
|
+
});
|
|
4471
|
+
} catch {
|
|
4472
|
+
}
|
|
4254
4473
|
stats.created++;
|
|
4255
4474
|
if (!docId) {
|
|
4256
4475
|
stats.newWithoutDocId++;
|
|
@@ -4289,6 +4508,15 @@ const csvService = ({ strapi: strapi2 }) => ({
|
|
|
4289
4508
|
strapi2.log.warn(`[bulk-updater] Auto-publish failed for ${docId}:`, pubErr);
|
|
4290
4509
|
}
|
|
4291
4510
|
}
|
|
4511
|
+
try {
|
|
4512
|
+
await recordContentHistoryVersion(strapi2, {
|
|
4513
|
+
uid,
|
|
4514
|
+
documentId: docId,
|
|
4515
|
+
userId: user?.id,
|
|
4516
|
+
statusOverride: publish && ct.options?.draftAndPublish ? "published" : void 0
|
|
4517
|
+
});
|
|
4518
|
+
} catch {
|
|
4519
|
+
}
|
|
4292
4520
|
stats.updated++;
|
|
4293
4521
|
stats.diffs.push({
|
|
4294
4522
|
uid,
|
|
@@ -4315,6 +4543,15 @@ const csvService = ({ strapi: strapi2 }) => ({
|
|
|
4315
4543
|
strapi2.log.warn(`[bulk-updater] Auto-publish failed for ${newDocId}:`, pubErr);
|
|
4316
4544
|
}
|
|
4317
4545
|
}
|
|
4546
|
+
try {
|
|
4547
|
+
await recordContentHistoryVersion(strapi2, {
|
|
4548
|
+
uid,
|
|
4549
|
+
documentId: newDocId,
|
|
4550
|
+
userId: user?.id,
|
|
4551
|
+
statusOverride: publish && ct.options?.draftAndPublish ? "published" : void 0
|
|
4552
|
+
});
|
|
4553
|
+
} catch {
|
|
4554
|
+
}
|
|
4318
4555
|
stats.created++;
|
|
4319
4556
|
if (!docId) {
|
|
4320
4557
|
stats.newWithoutDocId++;
|
|
@@ -33795,8 +34032,8 @@ const index = {
|
|
|
33795
34032
|
},
|
|
33796
34033
|
bootstrap({ strapi: strapi2 }) {
|
|
33797
34034
|
strapi2.documents.use(async (context, next) => {
|
|
34035
|
+
const params = context.params;
|
|
33798
34036
|
if (["create", "update"].includes(context.action)) {
|
|
33799
|
-
const params = context.params;
|
|
33800
34037
|
const data = params?.data;
|
|
33801
34038
|
if (data && typeof data === "object") {
|
|
33802
34039
|
let scanDataTree = function(obj) {
|
|
@@ -33896,8 +34133,113 @@ const index = {
|
|
|
33896
34133
|
}
|
|
33897
34134
|
}
|
|
33898
34135
|
}
|
|
33899
|
-
|
|
34136
|
+
const result = await next();
|
|
34137
|
+
return result;
|
|
34138
|
+
});
|
|
34139
|
+
strapi2.server.use(async (ctx, next) => {
|
|
34140
|
+
if (!ctx.path.startsWith("/content-manager/history-versions")) {
|
|
34141
|
+
await next();
|
|
34142
|
+
return;
|
|
34143
|
+
}
|
|
34144
|
+
await next();
|
|
34145
|
+
if (ctx.status === 404 || ctx.status === 405) {
|
|
34146
|
+
if (ctx.method === "GET" && ctx.path === "/content-manager/history-versions") {
|
|
34147
|
+
const { contentType, documentId, locale: locale2, page = 1, pageSize = 20 } = ctx.query;
|
|
34148
|
+
if (!contentType) return;
|
|
34149
|
+
const historyQuery = strapi2.db?.query?.("plugin::content-manager.history-version");
|
|
34150
|
+
if (!historyQuery) return;
|
|
34151
|
+
const pageNum = Math.max(1, parseInt(page, 10) || 1);
|
|
34152
|
+
const limit = Math.min(100, Math.max(1, parseInt(pageSize, 10) || 20));
|
|
34153
|
+
const whereClause = {
|
|
34154
|
+
contentType,
|
|
34155
|
+
...documentId ? { relatedDocumentId: documentId } : {},
|
|
34156
|
+
...locale2 ? { locale: locale2 } : {}
|
|
34157
|
+
};
|
|
34158
|
+
const [results, total] = await Promise.all([
|
|
34159
|
+
historyQuery.findMany({
|
|
34160
|
+
where: whereClause,
|
|
34161
|
+
populate: ["createdBy"],
|
|
34162
|
+
orderBy: { createdAt: "desc" },
|
|
34163
|
+
limit,
|
|
34164
|
+
offset: (pageNum - 1) * limit
|
|
34165
|
+
}),
|
|
34166
|
+
historyQuery.count({ where: whereClause })
|
|
34167
|
+
]);
|
|
34168
|
+
const sanitizedResults = (results || []).map((ver) => ({
|
|
34169
|
+
...ver,
|
|
34170
|
+
createdBy: ver.createdBy ? {
|
|
34171
|
+
id: ver.createdBy.id,
|
|
34172
|
+
firstname: ver.createdBy.firstname,
|
|
34173
|
+
lastname: ver.createdBy.lastname,
|
|
34174
|
+
username: ver.createdBy.username,
|
|
34175
|
+
email: ver.createdBy.email
|
|
34176
|
+
} : void 0,
|
|
34177
|
+
meta: {
|
|
34178
|
+
unknownAttributes: { added: {}, removed: {} }
|
|
34179
|
+
}
|
|
34180
|
+
}));
|
|
34181
|
+
ctx.status = 200;
|
|
34182
|
+
ctx.body = {
|
|
34183
|
+
data: sanitizedResults,
|
|
34184
|
+
meta: {
|
|
34185
|
+
pagination: {
|
|
34186
|
+
page: pageNum,
|
|
34187
|
+
pageSize: limit,
|
|
34188
|
+
pageCount: Math.ceil(total / limit) || 1,
|
|
34189
|
+
total
|
|
34190
|
+
}
|
|
34191
|
+
}
|
|
34192
|
+
};
|
|
34193
|
+
} else if (ctx.method === "PUT" && ctx.path.endsWith("/restore")) {
|
|
34194
|
+
const match = ctx.path.match(/\/content-manager\/history-versions\/([^/]+)\/restore/);
|
|
34195
|
+
const versionId = match?.[1];
|
|
34196
|
+
if (!versionId) return;
|
|
34197
|
+
const historyQuery = strapi2.db?.query?.("plugin::content-manager.history-version");
|
|
34198
|
+
const version = await historyQuery?.findOne?.({ where: { id: versionId } });
|
|
34199
|
+
if (!version) {
|
|
34200
|
+
ctx.status = 404;
|
|
34201
|
+
ctx.body = { error: "Version not found" };
|
|
34202
|
+
return;
|
|
34203
|
+
}
|
|
34204
|
+
const restored = await strapi2.documents(version.contentType).update({
|
|
34205
|
+
documentId: version.relatedDocumentId,
|
|
34206
|
+
locale: version.locale || void 0,
|
|
34207
|
+
data: version.data
|
|
34208
|
+
});
|
|
34209
|
+
await recordContentHistoryVersion(strapi2, {
|
|
34210
|
+
uid: version.contentType,
|
|
34211
|
+
documentId: version.relatedDocumentId,
|
|
34212
|
+
statusOverride: version.status || "published"
|
|
34213
|
+
});
|
|
34214
|
+
ctx.status = 200;
|
|
34215
|
+
ctx.body = {
|
|
34216
|
+
data: {
|
|
34217
|
+
documentId: restored?.documentId || version.relatedDocumentId
|
|
34218
|
+
}
|
|
34219
|
+
};
|
|
34220
|
+
}
|
|
34221
|
+
}
|
|
33900
34222
|
});
|
|
34223
|
+
try {
|
|
34224
|
+
const knex = strapi2.db?.connection;
|
|
34225
|
+
if (knex) {
|
|
34226
|
+
if (knex.client?.config?.client === "sqlite3" || knex.client?.dialect === "sqlite3") {
|
|
34227
|
+
knex.raw("PRAGMA busy_timeout = 10000;").catch(() => {
|
|
34228
|
+
});
|
|
34229
|
+
}
|
|
34230
|
+
knex.schema.hasTable("strapi_history_versions").then((hasTable) => {
|
|
34231
|
+
if (hasTable) {
|
|
34232
|
+
knex.raw(`
|
|
34233
|
+
CREATE INDEX IF NOT EXISTS idx_history_versions_lookup
|
|
34234
|
+
ON strapi_history_versions (content_type, related_document_id, created_at)
|
|
34235
|
+
`).catch(() => {
|
|
34236
|
+
});
|
|
34237
|
+
}
|
|
34238
|
+
}).catch(() => {
|
|
34239
|
+
});
|
|
34240
|
+
}
|
|
34241
|
+
} catch {
|
|
34242
|
+
}
|
|
33901
34243
|
},
|
|
33902
34244
|
routes,
|
|
33903
34245
|
contentTypes,
|
|
@@ -33911,7 +34253,8 @@ const index = {
|
|
|
33911
34253
|
bulkUpdater: bulkUpdaterService,
|
|
33912
34254
|
audit: auditService,
|
|
33913
34255
|
validationRules: validationRulesService,
|
|
33914
|
-
csv: csvService
|
|
34256
|
+
csv: csvService,
|
|
34257
|
+
contentHistory: contentHistoryService
|
|
33915
34258
|
}
|
|
33916
34259
|
};
|
|
33917
34260
|
export {
|