@strapi/content-manager 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.e9122b401c96877b6707775c4f893660eab93ae3
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/LICENSE +18 -3
- package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
- package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
- package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-CpBFh6_r.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-CpBFh6_r.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-_zF8p6CY.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-_zF8p6CY.js.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
- package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
- package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
- package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs → EditConfigurationPage-CE_yavTi.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-CE_yavTi.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-_aG2DJSU.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-_aG2DJSU.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-DeTn7rAF.mjs} +59 -48
- package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-G9uNzwYL.js} +58 -49
- package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +1 -0
- package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-CnCKhI1R.mjs} +995 -795
- package/dist/_chunks/Field-CnCKhI1R.mjs.map +1 -0
- package/dist/_chunks/{Field-DmVKIAOo.js → Field-DDHUWEfV.js} +1041 -842
- package/dist/_chunks/Field-DDHUWEfV.js.map +1 -0
- package/dist/_chunks/{Form-CPZC9vWa.js → Form-DYETaKUX.js} +65 -45
- package/dist/_chunks/Form-DYETaKUX.js.map +1 -0
- package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-IvVVwqRL.mjs} +65 -44
- package/dist/_chunks/Form-IvVVwqRL.mjs.map +1 -0
- package/dist/_chunks/{History-Dmr9fmUA.mjs → History-BMunT-do.mjs} +148 -54
- package/dist/_chunks/History-BMunT-do.mjs.map +1 -0
- package/dist/_chunks/{History-DeAPlvtv.js → History-CnZDctSO.js} +149 -56
- package/dist/_chunks/History-CnZDctSO.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-BynalOp8.js} +67 -58
- package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-CDqkCxgV.mjs} +63 -53
- package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-I88Ouzoq.js} +126 -137
- package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +1 -0
- package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-_5gS-DOF.mjs} +123 -134
- package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BaWQ7HsA.js} +3 -3
- package/dist/_chunks/NoContentTypePage-BaWQ7HsA.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Dht-55hr.mjs} +3 -3
- package/dist/_chunks/NoContentTypePage-Dht-55hr.mjs.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-Bs8D5W_v.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-Bs8D5W_v.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-DCVUh5at.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-DCVUh5at.js.map} +1 -1
- package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-BPgFQeGj.js} +71 -62
- package/dist/_chunks/Relations-BPgFQeGj.js.map +1 -0
- package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-Chdt5qWc.mjs} +67 -57
- package/dist/_chunks/Relations-Chdt5qWc.mjs.map +1 -0
- package/dist/_chunks/{en-C-V1_90f.js → en-BVzUkPxZ.js} +16 -8
- package/dist/_chunks/{en-C-V1_90f.js.map → en-BVzUkPxZ.js.map} +1 -1
- package/dist/_chunks/{en-MBPul9Su.mjs → en-CPTj6CjC.mjs} +16 -8
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-CPTj6CjC.mjs.map} +1 -1
- package/dist/_chunks/{index-C6AH2hEl.js → index-BhbLFX4l.js} +1752 -903
- package/dist/_chunks/index-BhbLFX4l.js.map +1 -0
- package/dist/_chunks/{index-CwRRo1V9.mjs → index-D4UGPFZC.mjs} +1778 -928
- package/dist/_chunks/index-D4UGPFZC.mjs.map +1 -0
- package/dist/_chunks/{layout-B_SXLhqf.js → layout-CYA7s0qO.js} +45 -29
- package/dist/_chunks/layout-CYA7s0qO.js.map +1 -0
- package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-D4HI4_PS.mjs} +45 -27
- package/dist/_chunks/layout-D4HI4_PS.mjs.map +1 -0
- package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-1pXaYpBK.mjs} +2 -2
- package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-1pXaYpBK.mjs.map} +1 -1
- package/dist/_chunks/{relations-iBMa_OFG.js → relations-DDZ9OxNo.js} +2 -2
- package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-DDZ9OxNo.js.map} +1 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js +28 -0
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
- package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +8 -7
- package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
- package/dist/admin/src/content-manager.d.ts +3 -3
- package/dist/admin/src/exports.d.ts +1 -0
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +5 -8
- package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
- package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
- package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
- package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
- package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
- package/dist/admin/src/services/api.d.ts +2 -3
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +5 -5
- package/dist/admin/src/services/documents.d.ts +31 -17
- package/dist/admin/src/services/init.d.ts +2 -2
- package/dist/admin/src/services/relations.d.ts +3 -3
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/api.d.ts +4 -18
- package/dist/admin/src/utils/validation.d.ts +5 -7
- package/dist/server/index.js +436 -281
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +444 -289
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/single-types.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/index.d.ts +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +18 -39
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts +13 -12
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +8 -29
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +18 -39
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts +8 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +17 -7
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/relations.d.ts +2 -2
- package/dist/shared/contracts/relations.d.ts.map +1 -1
- package/package.json +14 -15
- package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
- package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
- package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
- package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
- package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
- package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
- package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
- package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
- package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
- package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
- package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
- package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
- package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
- package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
- package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
- package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
- package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
- package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
- package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
- package/dist/_chunks/urls-DzZya_gm.js +0 -6
- package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
- package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
- package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
package/dist/server/index.js
CHANGED
@@ -199,7 +199,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
199
199
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
200
200
|
};
|
201
201
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
202
|
+
const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
|
202
203
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
204
|
+
const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
|
203
205
|
const getLocaleDictionary = async () => {
|
204
206
|
if (!localesService)
|
205
207
|
return {};
|
@@ -226,20 +228,25 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
226
228
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
227
229
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
228
230
|
};
|
229
|
-
const getDeepPopulate2 = (uid2) => {
|
231
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
230
232
|
const model = strapi2.getModel(uid2);
|
231
233
|
const attributes = Object.entries(model.attributes);
|
234
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
232
235
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
233
236
|
switch (attribute.type) {
|
234
237
|
case "relation": {
|
238
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
239
|
+
if (isMorphRelation) {
|
240
|
+
break;
|
241
|
+
}
|
235
242
|
const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
|
236
243
|
if (isVisible2) {
|
237
|
-
acc[attributeName] = {
|
244
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
238
245
|
}
|
239
246
|
break;
|
240
247
|
}
|
241
248
|
case "media": {
|
242
|
-
acc[attributeName] = {
|
249
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
243
250
|
break;
|
244
251
|
}
|
245
252
|
case "component": {
|
@@ -312,6 +319,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
312
319
|
getRelationRestoreValue,
|
313
320
|
getMediaRestoreValue,
|
314
321
|
getDefaultLocale,
|
322
|
+
isLocalizedContentType,
|
315
323
|
getLocaleDictionary,
|
316
324
|
getRetentionDays,
|
317
325
|
getVersionStatus,
|
@@ -334,7 +342,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
334
342
|
});
|
335
343
|
},
|
336
344
|
async findVersionsPage(params) {
|
337
|
-
const
|
345
|
+
const model = strapi2.getModel(params.query.contentType);
|
346
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
347
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
348
|
+
let locale = null;
|
349
|
+
if (isLocalizedContentType) {
|
350
|
+
locale = params.query.locale || defaultLocale;
|
351
|
+
}
|
338
352
|
const [{ results, pagination }, localeDictionary] = await Promise.all([
|
339
353
|
query.findPage({
|
340
354
|
...params.query,
|
@@ -490,13 +504,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
490
504
|
}
|
491
505
|
};
|
492
506
|
};
|
507
|
+
const shouldCreateHistoryVersion = (context) => {
|
508
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
509
|
+
return false;
|
510
|
+
}
|
511
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
512
|
+
return false;
|
513
|
+
}
|
514
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
515
|
+
return false;
|
516
|
+
}
|
517
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
518
|
+
return false;
|
519
|
+
}
|
520
|
+
return true;
|
521
|
+
};
|
522
|
+
const getSchemas = (uid2) => {
|
523
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
524
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
525
|
+
(currentComponentSchemas, key) => {
|
526
|
+
const fieldSchema = attributesSchema[key];
|
527
|
+
if (fieldSchema.type === "component") {
|
528
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
529
|
+
return {
|
530
|
+
...currentComponentSchemas,
|
531
|
+
[fieldSchema.component]: componentSchema
|
532
|
+
};
|
533
|
+
}
|
534
|
+
return currentComponentSchemas;
|
535
|
+
},
|
536
|
+
{}
|
537
|
+
);
|
538
|
+
return {
|
539
|
+
schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
|
540
|
+
componentsSchemas
|
541
|
+
};
|
542
|
+
};
|
493
543
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
494
544
|
const state = {
|
495
545
|
deleteExpiredJob: null,
|
496
546
|
isInitialized: false
|
497
547
|
};
|
498
|
-
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
499
|
-
const historyService = getService(strapi2, "history");
|
500
548
|
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
501
549
|
return {
|
502
550
|
async bootstrap() {
|
@@ -504,60 +552,53 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
504
552
|
return;
|
505
553
|
}
|
506
554
|
strapi2.documents.use(async (context, next) => {
|
507
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
508
|
-
return next();
|
509
|
-
}
|
510
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
511
|
-
return next();
|
512
|
-
}
|
513
|
-
const contentTypeUid = context.contentType.uid;
|
514
|
-
if (!contentTypeUid.startsWith("api::")) {
|
515
|
-
return next();
|
516
|
-
}
|
517
555
|
const result = await next();
|
518
|
-
|
556
|
+
if (!shouldCreateHistoryVersion(context)) {
|
557
|
+
return result;
|
558
|
+
}
|
559
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
519
560
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
520
|
-
const
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
561
|
+
const locales = fp.castArray(context.params?.locale || defaultLocale);
|
562
|
+
if (!locales.length) {
|
563
|
+
return result;
|
564
|
+
}
|
565
|
+
const uid2 = context.contentType.uid;
|
566
|
+
const schemas = getSchemas(uid2);
|
567
|
+
const model = strapi2.getModel(uid2);
|
568
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
569
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
570
|
+
where: {
|
571
|
+
documentId,
|
572
|
+
...isLocalizedContentType ? { locale: { $in: locales } } : {},
|
573
|
+
...strapiUtils.contentTypes.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
|
574
|
+
},
|
575
|
+
populate: serviceUtils.getDeepPopulate(
|
576
|
+
uid2,
|
577
|
+
true
|
578
|
+
/* use database syntax */
|
579
|
+
)
|
525
580
|
});
|
526
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
527
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
528
|
-
const componentsSchemas = Object.keys(
|
529
|
-
attributesSchema
|
530
|
-
).reduce((currentComponentSchemas, key) => {
|
531
|
-
const fieldSchema = attributesSchema[key];
|
532
|
-
if (fieldSchema.type === "component") {
|
533
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
534
|
-
return {
|
535
|
-
...currentComponentSchemas,
|
536
|
-
[fieldSchema.component]: componentSchema
|
537
|
-
};
|
538
|
-
}
|
539
|
-
return currentComponentSchemas;
|
540
|
-
}, {});
|
541
581
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
542
|
-
onCommit(() => {
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
582
|
+
onCommit(async () => {
|
583
|
+
for (const entry of localeEntries) {
|
584
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
585
|
+
await getService(strapi2, "history").createVersion({
|
586
|
+
contentType: uid2,
|
587
|
+
data: fp.omit(FIELDS_TO_IGNORE, entry),
|
588
|
+
relatedDocumentId: documentId,
|
589
|
+
locale: entry.locale,
|
590
|
+
status,
|
591
|
+
...schemas
|
592
|
+
});
|
593
|
+
}
|
552
594
|
});
|
553
595
|
});
|
554
596
|
return result;
|
555
597
|
});
|
556
|
-
const retentionDays = serviceUtils.getRetentionDays();
|
557
598
|
state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
|
558
|
-
const retentionDaysInMilliseconds =
|
599
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
559
600
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
560
|
-
query.deleteMany({
|
601
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
561
602
|
where: {
|
562
603
|
created_at: {
|
563
604
|
$lt: expirationDate.toISOString()
|
@@ -1189,6 +1230,11 @@ const { createPolicy } = strapiUtils.policy;
|
|
1189
1230
|
const hasPermissions = createPolicy({
|
1190
1231
|
name: "plugin::content-manager.hasPermissions",
|
1191
1232
|
validator: validateHasPermissionsInput,
|
1233
|
+
/**
|
1234
|
+
* NOTE: Action aliases are currently not checked at this level (policy).
|
1235
|
+
* This is currently the intended behavior to avoid changing the behavior of API related permissions.
|
1236
|
+
* If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
|
1237
|
+
*/
|
1192
1238
|
handler(ctx, config = {}) {
|
1193
1239
|
const { actions = [], hasAtLeastOne = false } = config;
|
1194
1240
|
const { userAbility } = ctx.state;
|
@@ -1478,7 +1524,7 @@ const { PaginationError, ValidationError } = strapiUtils.errors;
|
|
1478
1524
|
const TYPES = ["singleType", "collectionType"];
|
1479
1525
|
const kindSchema = strapiUtils.yup.string().oneOf(TYPES).nullable();
|
1480
1526
|
const bulkActionInputSchema = strapiUtils.yup.object({
|
1481
|
-
|
1527
|
+
documentIds: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
|
1482
1528
|
}).required();
|
1483
1529
|
const generateUIDInputSchema = strapiUtils.yup.object({
|
1484
1530
|
contentTypeUID: strapiUtils.yup.string().required(),
|
@@ -1577,15 +1623,49 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1577
1623
|
}
|
1578
1624
|
}, body);
|
1579
1625
|
};
|
1580
|
-
const
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1626
|
+
const singleLocaleSchema = strapiUtils.yup.string().nullable();
|
1627
|
+
const multipleLocaleSchema = strapiUtils.yup.lazy(
|
1628
|
+
(value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1629
|
+
);
|
1630
|
+
const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
|
1631
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1632
|
+
const { allowMultipleLocales } = opts;
|
1633
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1634
|
+
const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1635
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1636
|
+
const schema = strapiUtils.yup.object().shape({
|
1637
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1638
|
+
status: statusSchema
|
1639
|
+
});
|
1640
|
+
try {
|
1641
|
+
await strapiUtils.validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1642
|
+
return { locale, status, ...rest };
|
1643
|
+
} catch (error) {
|
1644
|
+
throw new strapiUtils.errors.ValidationError(`Validation error: ${error.message}`);
|
1587
1645
|
}
|
1588
|
-
|
1646
|
+
};
|
1647
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1648
|
+
const documentMetadata2 = getService$1("document-metadata");
|
1649
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1650
|
+
let {
|
1651
|
+
meta: { availableLocales, availableStatus }
|
1652
|
+
} = serviceOutput;
|
1653
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1654
|
+
availableLocales = await strapiUtils.async.map(
|
1655
|
+
availableLocales,
|
1656
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1657
|
+
);
|
1658
|
+
availableStatus = await strapiUtils.async.map(
|
1659
|
+
availableStatus,
|
1660
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1661
|
+
);
|
1662
|
+
return {
|
1663
|
+
...serviceOutput,
|
1664
|
+
meta: {
|
1665
|
+
availableLocales,
|
1666
|
+
availableStatus
|
1667
|
+
}
|
1668
|
+
};
|
1589
1669
|
};
|
1590
1670
|
const createDocument = async (ctx, opts) => {
|
1591
1671
|
const { userAbility, user } = ctx.state;
|
@@ -1600,7 +1680,7 @@ const createDocument = async (ctx, opts) => {
|
|
1600
1680
|
const setCreator = strapiUtils.setCreatorFields({ user });
|
1601
1681
|
const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
|
1602
1682
|
const sanitizedBody = await sanitizeFn(body);
|
1603
|
-
const { locale, status
|
1683
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1604
1684
|
return documentManager2.create(model, {
|
1605
1685
|
data: sanitizedBody,
|
1606
1686
|
locale,
|
@@ -1619,7 +1699,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1619
1699
|
}
|
1620
1700
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1621
1701
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1622
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1702
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1623
1703
|
const [documentVersion, documentExists] = await Promise.all([
|
1624
1704
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1625
1705
|
documentManager2.exists(model, id)
|
@@ -1657,7 +1737,7 @@ const collectionTypes = {
|
|
1657
1737
|
}
|
1658
1738
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1659
1739
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1660
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
1740
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1661
1741
|
const { results: documents, pagination } = await documentManager2.findPage(
|
1662
1742
|
{ ...permissionQuery, populate, locale, status },
|
1663
1743
|
model
|
@@ -1686,14 +1766,13 @@ const collectionTypes = {
|
|
1686
1766
|
const { userAbility } = ctx.state;
|
1687
1767
|
const { model, id } = ctx.params;
|
1688
1768
|
const documentManager2 = getService$1("document-manager");
|
1689
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1690
1769
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1691
1770
|
if (permissionChecker2.cannot.read()) {
|
1692
1771
|
return ctx.forbidden();
|
1693
1772
|
}
|
1694
1773
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1695
1774
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1696
|
-
const { locale, status
|
1775
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1697
1776
|
const version = await documentManager2.findOne(id, model, {
|
1698
1777
|
populate,
|
1699
1778
|
locale,
|
@@ -1704,9 +1783,11 @@ const collectionTypes = {
|
|
1704
1783
|
if (!exists) {
|
1705
1784
|
return ctx.notFound();
|
1706
1785
|
}
|
1707
|
-
const { meta } = await
|
1786
|
+
const { meta } = await formatDocumentWithMetadata(
|
1787
|
+
permissionChecker2,
|
1708
1788
|
model,
|
1709
|
-
|
1789
|
+
// @ts-expect-error TODO: fix
|
1790
|
+
{ documentId: id, locale, publishedAt: null },
|
1710
1791
|
{ availableLocales: true, availableStatus: false }
|
1711
1792
|
);
|
1712
1793
|
ctx.body = { data: {}, meta };
|
@@ -1716,12 +1797,11 @@ const collectionTypes = {
|
|
1716
1797
|
return ctx.forbidden();
|
1717
1798
|
}
|
1718
1799
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1719
|
-
ctx.body = await
|
1800
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1720
1801
|
},
|
1721
1802
|
async create(ctx) {
|
1722
1803
|
const { userAbility } = ctx.state;
|
1723
1804
|
const { model } = ctx.params;
|
1724
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1725
1805
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1726
1806
|
const [totalEntries, document] = await Promise.all([
|
1727
1807
|
strapi.db.query(model).count(),
|
@@ -1729,7 +1809,7 @@ const collectionTypes = {
|
|
1729
1809
|
]);
|
1730
1810
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1731
1811
|
ctx.status = 201;
|
1732
|
-
ctx.body = await
|
1812
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1733
1813
|
// Empty metadata as it's not relevant for a new document
|
1734
1814
|
availableLocales: false,
|
1735
1815
|
availableStatus: false
|
@@ -1743,25 +1823,23 @@ const collectionTypes = {
|
|
1743
1823
|
async update(ctx) {
|
1744
1824
|
const { userAbility } = ctx.state;
|
1745
1825
|
const { model } = ctx.params;
|
1746
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1747
1826
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1748
1827
|
const updatedVersion = await updateDocument(ctx);
|
1749
1828
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1750
|
-
ctx.body = await
|
1829
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1751
1830
|
},
|
1752
1831
|
async clone(ctx) {
|
1753
1832
|
const { userAbility, user } = ctx.state;
|
1754
1833
|
const { model, sourceId: id } = ctx.params;
|
1755
1834
|
const { body } = ctx.request;
|
1756
1835
|
const documentManager2 = getService$1("document-manager");
|
1757
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1758
1836
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1759
1837
|
if (permissionChecker2.cannot.create()) {
|
1760
1838
|
return ctx.forbidden();
|
1761
1839
|
}
|
1762
1840
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1763
1841
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1764
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1842
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1765
1843
|
const document = await documentManager2.findOne(id, model, {
|
1766
1844
|
populate,
|
1767
1845
|
locale,
|
@@ -1777,7 +1855,7 @@ const collectionTypes = {
|
|
1777
1855
|
const sanitizedBody = await sanitizeFn(body);
|
1778
1856
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1779
1857
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1780
|
-
ctx.body = await
|
1858
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1781
1859
|
// Empty metadata as it's not relevant for a new document
|
1782
1860
|
availableLocales: false,
|
1783
1861
|
availableStatus: false
|
@@ -1806,7 +1884,7 @@ const collectionTypes = {
|
|
1806
1884
|
}
|
1807
1885
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1808
1886
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1809
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
1887
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1810
1888
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1811
1889
|
if (documentLocales.length === 0) {
|
1812
1890
|
return ctx.notFound();
|
@@ -1828,7 +1906,6 @@ const collectionTypes = {
|
|
1828
1906
|
const { id, model } = ctx.params;
|
1829
1907
|
const { body } = ctx.request;
|
1830
1908
|
const documentManager2 = getService$1("document-manager");
|
1831
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1832
1909
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1833
1910
|
if (permissionChecker2.cannot.publish()) {
|
1834
1911
|
return ctx.forbidden();
|
@@ -1836,25 +1913,46 @@ const collectionTypes = {
|
|
1836
1913
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1837
1914
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1838
1915
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1839
|
-
|
1916
|
+
let document;
|
1917
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1918
|
+
const isCreate = fp.isNil(id);
|
1919
|
+
if (isCreate) {
|
1920
|
+
if (permissionChecker2.cannot.create()) {
|
1921
|
+
throw new strapiUtils.errors.ForbiddenError();
|
1922
|
+
}
|
1923
|
+
document = await createDocument(ctx, { populate });
|
1924
|
+
}
|
1925
|
+
const isUpdate = !isCreate;
|
1926
|
+
if (isUpdate) {
|
1927
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
1928
|
+
if (!document) {
|
1929
|
+
throw new strapiUtils.errors.NotFoundError("Document not found");
|
1930
|
+
}
|
1931
|
+
if (permissionChecker2.can.update(document)) {
|
1932
|
+
await updateDocument(ctx);
|
1933
|
+
}
|
1934
|
+
}
|
1840
1935
|
if (permissionChecker2.cannot.publish(document)) {
|
1841
1936
|
throw new strapiUtils.errors.ForbiddenError();
|
1842
1937
|
}
|
1843
|
-
const
|
1844
|
-
return documentManager2.publish(document.documentId, model, {
|
1938
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1845
1939
|
locale
|
1846
1940
|
// TODO: Allow setting creator fields on publish
|
1847
1941
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1848
1942
|
});
|
1943
|
+
if (!publishResult || publishResult.length === 0) {
|
1944
|
+
throw new strapiUtils.errors.NotFoundError("Document not found or already published.");
|
1945
|
+
}
|
1946
|
+
return publishResult[0];
|
1849
1947
|
});
|
1850
1948
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1851
|
-
ctx.body = await
|
1949
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1852
1950
|
},
|
1853
1951
|
async bulkPublish(ctx) {
|
1854
1952
|
const { userAbility } = ctx.state;
|
1855
1953
|
const { model } = ctx.params;
|
1856
1954
|
const { body } = ctx.request;
|
1857
|
-
const {
|
1955
|
+
const { documentIds } = body;
|
1858
1956
|
await validateBulkActionInput(body);
|
1859
1957
|
const documentManager2 = getService$1("document-manager");
|
1860
1958
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1863,8 +1961,13 @@ const collectionTypes = {
|
|
1863
1961
|
}
|
1864
1962
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1865
1963
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1866
|
-
const
|
1867
|
-
|
1964
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1965
|
+
allowMultipleLocales: true
|
1966
|
+
});
|
1967
|
+
const entityPromises = documentIds.map(
|
1968
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1969
|
+
);
|
1970
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1868
1971
|
for (const entity of entities) {
|
1869
1972
|
if (!entity) {
|
1870
1973
|
return ctx.notFound();
|
@@ -1873,24 +1976,27 @@ const collectionTypes = {
|
|
1873
1976
|
return ctx.forbidden();
|
1874
1977
|
}
|
1875
1978
|
}
|
1876
|
-
const
|
1979
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1877
1980
|
ctx.body = { count };
|
1878
1981
|
},
|
1879
1982
|
async bulkUnpublish(ctx) {
|
1880
1983
|
const { userAbility } = ctx.state;
|
1881
1984
|
const { model } = ctx.params;
|
1882
1985
|
const { body } = ctx.request;
|
1883
|
-
const {
|
1986
|
+
const { documentIds } = body;
|
1884
1987
|
await validateBulkActionInput(body);
|
1885
1988
|
const documentManager2 = getService$1("document-manager");
|
1886
1989
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1887
1990
|
if (permissionChecker2.cannot.unpublish()) {
|
1888
1991
|
return ctx.forbidden();
|
1889
1992
|
}
|
1890
|
-
const
|
1891
|
-
|
1892
|
-
|
1893
|
-
const
|
1993
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1994
|
+
allowMultipleLocales: true
|
1995
|
+
});
|
1996
|
+
const entityPromises = documentIds.map(
|
1997
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1998
|
+
);
|
1999
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1894
2000
|
for (const entity of entities) {
|
1895
2001
|
if (!entity) {
|
1896
2002
|
return ctx.notFound();
|
@@ -1899,7 +2005,8 @@ const collectionTypes = {
|
|
1899
2005
|
return ctx.forbidden();
|
1900
2006
|
}
|
1901
2007
|
}
|
1902
|
-
const
|
2008
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
2009
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1903
2010
|
ctx.body = { count };
|
1904
2011
|
},
|
1905
2012
|
async unpublish(ctx) {
|
@@ -1909,7 +2016,6 @@ const collectionTypes = {
|
|
1909
2016
|
body: { discardDraft, ...body }
|
1910
2017
|
} = ctx.request;
|
1911
2018
|
const documentManager2 = getService$1("document-manager");
|
1912
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1913
2019
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1914
2020
|
if (permissionChecker2.cannot.unpublish()) {
|
1915
2021
|
return ctx.forbidden();
|
@@ -1919,7 +2025,7 @@ const collectionTypes = {
|
|
1919
2025
|
}
|
1920
2026
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1921
2027
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1922
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2028
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1923
2029
|
const document = await documentManager2.findOne(id, model, {
|
1924
2030
|
populate,
|
1925
2031
|
locale,
|
@@ -1941,7 +2047,7 @@ const collectionTypes = {
|
|
1941
2047
|
ctx.body = await strapiUtils.async.pipe(
|
1942
2048
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1943
2049
|
permissionChecker2.sanitizeOutput,
|
1944
|
-
(document2) =>
|
2050
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1945
2051
|
)(document);
|
1946
2052
|
});
|
1947
2053
|
},
|
@@ -1950,14 +2056,13 @@ const collectionTypes = {
|
|
1950
2056
|
const { id, model } = ctx.params;
|
1951
2057
|
const { body } = ctx.request;
|
1952
2058
|
const documentManager2 = getService$1("document-manager");
|
1953
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1954
2059
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1955
2060
|
if (permissionChecker2.cannot.discard()) {
|
1956
2061
|
return ctx.forbidden();
|
1957
2062
|
}
|
1958
2063
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1959
2064
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1960
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2065
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1961
2066
|
const document = await documentManager2.findOne(id, model, {
|
1962
2067
|
populate,
|
1963
2068
|
locale,
|
@@ -1972,14 +2077,14 @@ const collectionTypes = {
|
|
1972
2077
|
ctx.body = await strapiUtils.async.pipe(
|
1973
2078
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1974
2079
|
permissionChecker2.sanitizeOutput,
|
1975
|
-
(document2) =>
|
2080
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1976
2081
|
)(document);
|
1977
2082
|
},
|
1978
2083
|
async bulkDelete(ctx) {
|
1979
2084
|
const { userAbility } = ctx.state;
|
1980
2085
|
const { model } = ctx.params;
|
1981
2086
|
const { query, body } = ctx.request;
|
1982
|
-
const {
|
2087
|
+
const { documentIds } = body;
|
1983
2088
|
await validateBulkActionInput(body);
|
1984
2089
|
const documentManager2 = getService$1("document-manager");
|
1985
2090
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1987,14 +2092,22 @@ const collectionTypes = {
|
|
1987
2092
|
return ctx.forbidden();
|
1988
2093
|
}
|
1989
2094
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1990
|
-
const
|
1991
|
-
const
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
2095
|
+
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2096
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2097
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2098
|
+
populate,
|
2099
|
+
locale
|
2100
|
+
});
|
2101
|
+
if (documentLocales.length === 0) {
|
2102
|
+
return ctx.notFound();
|
2103
|
+
}
|
2104
|
+
for (const document of documentLocales) {
|
2105
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2106
|
+
return ctx.forbidden();
|
1995
2107
|
}
|
1996
|
-
}
|
1997
|
-
const
|
2108
|
+
}
|
2109
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2110
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1998
2111
|
ctx.body = { count };
|
1999
2112
|
},
|
2000
2113
|
async countDraftRelations(ctx) {
|
@@ -2007,7 +2120,7 @@ const collectionTypes = {
|
|
2007
2120
|
}
|
2008
2121
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2009
2122
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2010
|
-
const { locale, status
|
2123
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
2011
2124
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
2012
2125
|
if (!entity) {
|
2013
2126
|
return ctx.notFound();
|
@@ -2022,7 +2135,7 @@ const collectionTypes = {
|
|
2022
2135
|
},
|
2023
2136
|
async countManyEntriesDraftRelations(ctx) {
|
2024
2137
|
const { userAbility } = ctx.state;
|
2025
|
-
const ids = ctx.request.query.
|
2138
|
+
const ids = ctx.request.query.documentIds;
|
2026
2139
|
const locale = ctx.request.query.locale;
|
2027
2140
|
const { model } = ctx.params;
|
2028
2141
|
const documentManager2 = getService$1("document-manager");
|
@@ -2030,16 +2143,16 @@ const collectionTypes = {
|
|
2030
2143
|
if (permissionChecker2.cannot.read()) {
|
2031
2144
|
return ctx.forbidden();
|
2032
2145
|
}
|
2033
|
-
const
|
2146
|
+
const documents = await documentManager2.findMany(
|
2034
2147
|
{
|
2035
2148
|
filters: {
|
2036
|
-
|
2149
|
+
documentId: ids
|
2037
2150
|
},
|
2038
2151
|
locale
|
2039
2152
|
},
|
2040
2153
|
model
|
2041
2154
|
);
|
2042
|
-
if (!
|
2155
|
+
if (!documents) {
|
2043
2156
|
return ctx.notFound();
|
2044
2157
|
}
|
2045
2158
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2230,20 +2343,13 @@ const sanitizeMainField = (model, mainField, userAbility) => {
|
|
2230
2343
|
userAbility,
|
2231
2344
|
model: model.uid
|
2232
2345
|
});
|
2233
|
-
|
2346
|
+
const isMainFieldListable = isListable(model, mainField);
|
2347
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2348
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2234
2349
|
return "id";
|
2235
2350
|
}
|
2236
|
-
if (
|
2237
|
-
|
2238
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2239
|
-
userAbility,
|
2240
|
-
model: "plugin::users-permissions.user"
|
2241
|
-
});
|
2242
|
-
if (userPermissionChecker.can.read()) {
|
2243
|
-
return "name";
|
2244
|
-
}
|
2245
|
-
}
|
2246
|
-
return "id";
|
2351
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2352
|
+
return "name";
|
2247
2353
|
}
|
2248
2354
|
return mainField;
|
2249
2355
|
};
|
@@ -2501,9 +2607,7 @@ const relations = {
|
|
2501
2607
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2502
2608
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2503
2609
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2504
|
-
ordering: "desc"
|
2505
|
-
page: ctx.request.query.page,
|
2506
|
-
pageSize: ctx.request.query.pageSize
|
2610
|
+
ordering: "desc"
|
2507
2611
|
});
|
2508
2612
|
const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
|
2509
2613
|
ctx.body = {
|
@@ -2535,7 +2639,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2535
2639
|
throw new strapiUtils.errors.ForbiddenError();
|
2536
2640
|
}
|
2537
2641
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2538
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2642
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2539
2643
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2540
2644
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2541
2645
|
// Find the first document to check if it exists
|
@@ -2572,12 +2676,11 @@ const singleTypes = {
|
|
2572
2676
|
const { model } = ctx.params;
|
2573
2677
|
const { query = {} } = ctx.request;
|
2574
2678
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2575
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2576
2679
|
if (permissionChecker2.cannot.read()) {
|
2577
2680
|
return ctx.forbidden();
|
2578
2681
|
}
|
2579
2682
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2580
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2683
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2581
2684
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2582
2685
|
if (!version) {
|
2583
2686
|
if (permissionChecker2.cannot.create()) {
|
@@ -2587,8 +2690,10 @@ const singleTypes = {
|
|
2587
2690
|
if (!document) {
|
2588
2691
|
return ctx.notFound();
|
2589
2692
|
}
|
2590
|
-
const { meta } = await
|
2693
|
+
const { meta } = await formatDocumentWithMetadata(
|
2694
|
+
permissionChecker2,
|
2591
2695
|
model,
|
2696
|
+
// @ts-expect-error - fix types
|
2592
2697
|
{ id: document.documentId, locale, publishedAt: null },
|
2593
2698
|
{ availableLocales: true, availableStatus: false }
|
2594
2699
|
);
|
@@ -2599,16 +2704,15 @@ const singleTypes = {
|
|
2599
2704
|
return ctx.forbidden();
|
2600
2705
|
}
|
2601
2706
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2602
|
-
ctx.body = await
|
2707
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2603
2708
|
},
|
2604
2709
|
async createOrUpdate(ctx) {
|
2605
2710
|
const { userAbility } = ctx.state;
|
2606
2711
|
const { model } = ctx.params;
|
2607
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2608
2712
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2609
2713
|
const document = await createOrUpdateDocument(ctx);
|
2610
2714
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2611
|
-
ctx.body = await
|
2715
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2612
2716
|
},
|
2613
2717
|
async delete(ctx) {
|
2614
2718
|
const { userAbility } = ctx.state;
|
@@ -2621,7 +2725,7 @@ const singleTypes = {
|
|
2621
2725
|
}
|
2622
2726
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2623
2727
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2624
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2728
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2625
2729
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2626
2730
|
populate,
|
2627
2731
|
locale
|
@@ -2644,7 +2748,6 @@ const singleTypes = {
|
|
2644
2748
|
const { model } = ctx.params;
|
2645
2749
|
const { query = {} } = ctx.request;
|
2646
2750
|
const documentManager2 = getService$1("document-manager");
|
2647
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2648
2751
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2649
2752
|
if (permissionChecker2.cannot.publish()) {
|
2650
2753
|
return ctx.forbidden();
|
@@ -2659,11 +2762,12 @@ const singleTypes = {
|
|
2659
2762
|
if (permissionChecker2.cannot.publish(document)) {
|
2660
2763
|
throw new strapiUtils.errors.ForbiddenError();
|
2661
2764
|
}
|
2662
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2663
|
-
|
2765
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2766
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2767
|
+
return publishResult.at(0);
|
2664
2768
|
});
|
2665
2769
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2666
|
-
ctx.body = await
|
2770
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2667
2771
|
},
|
2668
2772
|
async unpublish(ctx) {
|
2669
2773
|
const { userAbility } = ctx.state;
|
@@ -2673,7 +2777,6 @@ const singleTypes = {
|
|
2673
2777
|
query = {}
|
2674
2778
|
} = ctx.request;
|
2675
2779
|
const documentManager2 = getService$1("document-manager");
|
2676
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2677
2780
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2678
2781
|
if (permissionChecker2.cannot.unpublish()) {
|
2679
2782
|
return ctx.forbidden();
|
@@ -2682,7 +2785,7 @@ const singleTypes = {
|
|
2682
2785
|
return ctx.forbidden();
|
2683
2786
|
}
|
2684
2787
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2685
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2788
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2686
2789
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2687
2790
|
if (!document) {
|
2688
2791
|
return ctx.notFound();
|
@@ -2700,7 +2803,7 @@ const singleTypes = {
|
|
2700
2803
|
ctx.body = await strapiUtils.async.pipe(
|
2701
2804
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2702
2805
|
permissionChecker2.sanitizeOutput,
|
2703
|
-
(document2) =>
|
2806
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2704
2807
|
)(document);
|
2705
2808
|
});
|
2706
2809
|
},
|
@@ -2709,13 +2812,12 @@ const singleTypes = {
|
|
2709
2812
|
const { model } = ctx.params;
|
2710
2813
|
const { body, query = {} } = ctx.request;
|
2711
2814
|
const documentManager2 = getService$1("document-manager");
|
2712
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2713
2815
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2714
2816
|
if (permissionChecker2.cannot.discard()) {
|
2715
2817
|
return ctx.forbidden();
|
2716
2818
|
}
|
2717
2819
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2718
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2820
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2719
2821
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2720
2822
|
if (!document) {
|
2721
2823
|
return ctx.notFound();
|
@@ -2726,7 +2828,7 @@ const singleTypes = {
|
|
2726
2828
|
ctx.body = await strapiUtils.async.pipe(
|
2727
2829
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2728
2830
|
permissionChecker2.sanitizeOutput,
|
2729
|
-
(document2) =>
|
2831
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2730
2832
|
)(document);
|
2731
2833
|
},
|
2732
2834
|
async countDraftRelations(ctx) {
|
@@ -2735,7 +2837,7 @@ const singleTypes = {
|
|
2735
2837
|
const { query } = ctx.request;
|
2736
2838
|
const documentManager2 = getService$1("document-manager");
|
2737
2839
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2738
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2840
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2739
2841
|
if (permissionChecker2.cannot.read()) {
|
2740
2842
|
return ctx.forbidden();
|
2741
2843
|
}
|
@@ -2756,7 +2858,7 @@ const uid$1 = {
|
|
2756
2858
|
async generateUID(ctx) {
|
2757
2859
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2758
2860
|
const { query = {} } = ctx.request;
|
2759
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2861
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2760
2862
|
await validateUIDField(contentTypeUID, field);
|
2761
2863
|
const uidService = getService$1("uid");
|
2762
2864
|
ctx.body = {
|
@@ -2768,7 +2870,7 @@ const uid$1 = {
|
|
2768
2870
|
ctx.request.body
|
2769
2871
|
);
|
2770
2872
|
const { query = {} } = ctx.request;
|
2771
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2873
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2772
2874
|
await validateUIDField(contentTypeUID, field);
|
2773
2875
|
const uidService = getService$1("uid");
|
2774
2876
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -3411,12 +3513,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3411
3513
|
ability: userAbility,
|
3412
3514
|
model
|
3413
3515
|
});
|
3414
|
-
const
|
3516
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3517
|
+
const toSubject = (entity) => {
|
3518
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3519
|
+
};
|
3415
3520
|
const can = (action, entity, field) => {
|
3416
|
-
|
3521
|
+
const subject = toSubject(entity);
|
3522
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3523
|
+
return (
|
3524
|
+
// Test the original action to see if it passes
|
3525
|
+
userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
|
3526
|
+
aliases.some((alias) => userAbility.can(alias, subject, field))
|
3527
|
+
);
|
3417
3528
|
};
|
3418
3529
|
const cannot = (action, entity, field) => {
|
3419
|
-
|
3530
|
+
const subject = toSubject(entity);
|
3531
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3532
|
+
return (
|
3533
|
+
// Test both the original action
|
3534
|
+
userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
|
3535
|
+
aliases.every((alias) => userAbility.cannot(alias, subject, field))
|
3536
|
+
);
|
3420
3537
|
};
|
3421
3538
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3422
3539
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3559,7 +3676,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3559
3676
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3560
3677
|
}
|
3561
3678
|
});
|
3562
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils__default.default.contentTypes;
|
3679
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils__default.default.contentTypes;
|
3563
3680
|
const { isAnyToMany } = strapiUtils__default.default.relations;
|
3564
3681
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils__default.default.contentTypes.constants;
|
3565
3682
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3650,6 +3767,42 @@ const getDeepPopulate = (uid2, {
|
|
3650
3767
|
{}
|
3651
3768
|
);
|
3652
3769
|
};
|
3770
|
+
const getValidatableFieldsPopulate = (uid2, {
|
3771
|
+
initialPopulate = {},
|
3772
|
+
countMany = false,
|
3773
|
+
countOne = false,
|
3774
|
+
maxLevel = Infinity
|
3775
|
+
} = {}, level = 1) => {
|
3776
|
+
if (level > maxLevel) {
|
3777
|
+
return {};
|
3778
|
+
}
|
3779
|
+
const model = strapi.getModel(uid2);
|
3780
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3781
|
+
if (!getDoesAttributeRequireValidation(attribute)) {
|
3782
|
+
return populateAcc;
|
3783
|
+
}
|
3784
|
+
if (isScalarAttribute(attribute)) {
|
3785
|
+
return fp.merge(populateAcc, {
|
3786
|
+
[attributeName]: true
|
3787
|
+
});
|
3788
|
+
}
|
3789
|
+
return fp.merge(
|
3790
|
+
populateAcc,
|
3791
|
+
getPopulateFor(
|
3792
|
+
attributeName,
|
3793
|
+
model,
|
3794
|
+
{
|
3795
|
+
// @ts-expect-error - improve types
|
3796
|
+
initialPopulate: initialPopulate?.[attributeName],
|
3797
|
+
countMany,
|
3798
|
+
countOne,
|
3799
|
+
maxLevel
|
3800
|
+
},
|
3801
|
+
level
|
3802
|
+
)
|
3803
|
+
);
|
3804
|
+
}, {});
|
3805
|
+
};
|
3653
3806
|
const getDeepPopulateDraftCount = (uid2) => {
|
3654
3807
|
const model = strapi.getModel(uid2);
|
3655
3808
|
let hasRelations = false;
|
@@ -3657,6 +3810,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3657
3810
|
const attribute = model.attributes[attributeName];
|
3658
3811
|
switch (attribute.type) {
|
3659
3812
|
case "relation": {
|
3813
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
3814
|
+
if (isMorphRelation) {
|
3815
|
+
break;
|
3816
|
+
}
|
3660
3817
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3661
3818
|
populateAcc[attributeName] = {
|
3662
3819
|
count: true,
|
@@ -3671,22 +3828,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3671
3828
|
attribute.component
|
3672
3829
|
);
|
3673
3830
|
if (childHasRelations) {
|
3674
|
-
populateAcc[attributeName] = {
|
3831
|
+
populateAcc[attributeName] = {
|
3832
|
+
populate: populate2
|
3833
|
+
};
|
3675
3834
|
hasRelations = true;
|
3676
3835
|
}
|
3677
3836
|
break;
|
3678
3837
|
}
|
3679
3838
|
case "dynamiczone": {
|
3680
|
-
const
|
3681
|
-
const { populate:
|
3682
|
-
if (
|
3839
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
3840
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
3841
|
+
if (componentHasRelations) {
|
3683
3842
|
hasRelations = true;
|
3684
|
-
return
|
3843
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3685
3844
|
}
|
3686
3845
|
return acc;
|
3687
3846
|
}, {});
|
3688
|
-
if (!fp.isEmpty(
|
3689
|
-
populateAcc[attributeName] = {
|
3847
|
+
if (!fp.isEmpty(dzPopulateFragment)) {
|
3848
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3690
3849
|
}
|
3691
3850
|
break;
|
3692
3851
|
}
|
@@ -3878,41 +4037,70 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3878
4037
|
"updatedBy",
|
3879
4038
|
"status"
|
3880
4039
|
];
|
3881
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
4040
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
4041
|
+
"id",
|
4042
|
+
"locale",
|
4043
|
+
"updatedAt",
|
4044
|
+
"createdAt",
|
4045
|
+
"status",
|
4046
|
+
"publishedAt",
|
4047
|
+
"documentId"
|
4048
|
+
];
|
3882
4049
|
const CONTENT_MANAGER_STATUS = {
|
3883
4050
|
PUBLISHED: "published",
|
3884
4051
|
DRAFT: "draft",
|
3885
4052
|
MODIFIED: "modified"
|
3886
4053
|
};
|
3887
|
-
const
|
3888
|
-
if (!
|
4054
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
4055
|
+
if (!version || !version.updatedAt) {
|
3889
4056
|
return false;
|
3890
4057
|
}
|
3891
|
-
const
|
3892
|
-
const
|
3893
|
-
|
3894
|
-
return difference <= threshold;
|
4058
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
4059
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
4060
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3895
4061
|
};
|
3896
4062
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3897
4063
|
/**
|
3898
4064
|
* Returns available locales of a document for the current status
|
3899
4065
|
*/
|
3900
|
-
getAvailableLocales(uid2, version, allVersions) {
|
4066
|
+
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3901
4067
|
const versionsByLocale = fp.groupBy("locale", allVersions);
|
3902
4068
|
delete versionsByLocale[version.locale];
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
4069
|
+
const model = strapi2.getModel(uid2);
|
4070
|
+
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
4071
|
+
const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
|
4072
|
+
({ key }, { remove }) => {
|
4073
|
+
if (keysToKeep.includes(key)) {
|
4074
|
+
return;
|
4075
|
+
}
|
4076
|
+
remove(key);
|
4077
|
+
},
|
4078
|
+
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
4079
|
+
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
4080
|
+
localeVersion
|
4081
|
+
);
|
4082
|
+
const mappingResult = await strapiUtils.async.map(
|
4083
|
+
Object.values(versionsByLocale),
|
4084
|
+
async (localeVersions) => {
|
4085
|
+
const mappedLocaleVersions = await strapiUtils.async.map(
|
4086
|
+
localeVersions,
|
4087
|
+
traversalFunction
|
4088
|
+
);
|
4089
|
+
if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
|
4090
|
+
return mappedLocaleVersions[0];
|
4091
|
+
}
|
4092
|
+
const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
|
4093
|
+
const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
|
4094
|
+
if (!draftVersion) {
|
4095
|
+
return;
|
4096
|
+
}
|
4097
|
+
return {
|
4098
|
+
...draftVersion,
|
4099
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4100
|
+
};
|
3906
4101
|
}
|
3907
|
-
|
3908
|
-
|
3909
|
-
if (!draftVersion)
|
3910
|
-
return;
|
3911
|
-
return {
|
3912
|
-
...fp.pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
|
3913
|
-
status: this.getStatus(draftVersion, otherVersions)
|
3914
|
-
};
|
3915
|
-
}).filter(Boolean);
|
4102
|
+
);
|
4103
|
+
return mappingResult.filter(Boolean);
|
3916
4104
|
},
|
3917
4105
|
/**
|
3918
4106
|
* Returns available status of a document for the current locale
|
@@ -3950,26 +4138,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3950
4138
|
});
|
3951
4139
|
},
|
3952
4140
|
getStatus(version, otherDocumentStatuses) {
|
3953
|
-
|
3954
|
-
|
3955
|
-
|
4141
|
+
let draftVersion;
|
4142
|
+
let publishedVersion;
|
4143
|
+
if (version.publishedAt) {
|
4144
|
+
publishedVersion = version;
|
4145
|
+
} else {
|
4146
|
+
draftVersion = version;
|
3956
4147
|
}
|
3957
|
-
|
3958
|
-
|
3959
|
-
|
3960
|
-
|
3961
|
-
|
4148
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4149
|
+
if (otherVersion?.publishedAt) {
|
4150
|
+
publishedVersion = otherVersion;
|
4151
|
+
} else if (otherVersion) {
|
4152
|
+
draftVersion = otherVersion;
|
3962
4153
|
}
|
3963
|
-
if (
|
4154
|
+
if (!draftVersion)
|
3964
4155
|
return CONTENT_MANAGER_STATUS.PUBLISHED;
|
3965
|
-
|
3966
|
-
|
4156
|
+
if (!publishedVersion)
|
4157
|
+
return CONTENT_MANAGER_STATUS.DRAFT;
|
4158
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4159
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3967
4160
|
},
|
4161
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4162
|
+
// We could refactor this so the locales are only loaded when they're
|
4163
|
+
// needed. e.g. in the bulk locale action modal.
|
3968
4164
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4165
|
+
const populate = getValidatableFieldsPopulate(uid2);
|
3969
4166
|
const versions = await strapi2.db.query(uid2).findMany({
|
3970
4167
|
where: { documentId: version.documentId },
|
3971
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
3972
4168
|
populate: {
|
4169
|
+
// Populate only fields that require validation for bulk locale actions
|
4170
|
+
...populate,
|
4171
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3973
4172
|
createdBy: {
|
3974
4173
|
select: ["id", "firstname", "lastname", "email"]
|
3975
4174
|
},
|
@@ -3978,7 +4177,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3978
4177
|
}
|
3979
4178
|
}
|
3980
4179
|
});
|
3981
|
-
const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
|
4180
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
|
3982
4181
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3983
4182
|
return {
|
3984
4183
|
availableLocales: availableLocalesResult,
|
@@ -3991,8 +4190,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3991
4190
|
* - Available status of the document for the current locale
|
3992
4191
|
*/
|
3993
4192
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3994
|
-
if (!document)
|
3995
|
-
return
|
4193
|
+
if (!document) {
|
4194
|
+
return {
|
4195
|
+
data: document,
|
4196
|
+
meta: {
|
4197
|
+
availableLocales: [],
|
4198
|
+
availableStatus: []
|
4199
|
+
}
|
4200
|
+
};
|
4201
|
+
}
|
3996
4202
|
const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
|
3997
4203
|
if (!hasDraftAndPublish) {
|
3998
4204
|
opts.availableStatus = false;
|
@@ -4042,26 +4248,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
4042
4248
|
}, 0);
|
4043
4249
|
};
|
4044
4250
|
const { ApplicationError } = strapiUtils.errors;
|
4045
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
4046
4251
|
const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
|
4047
4252
|
const omitPublishedAtField = fp.omit(PUBLISHED_AT_ATTRIBUTE);
|
4048
4253
|
const omitIdField = fp.omit("id");
|
4049
|
-
const emitEvent = async (uid2, event, document) => {
|
4050
|
-
const modelDef = strapi.getModel(uid2);
|
4051
|
-
const sanitizedDocument = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
|
4052
|
-
{
|
4053
|
-
schema: modelDef,
|
4054
|
-
getModel(uid22) {
|
4055
|
-
return strapi.getModel(uid22);
|
4056
|
-
}
|
4057
|
-
},
|
4058
|
-
document
|
4059
|
-
);
|
4060
|
-
strapi.eventHub.emit(event, {
|
4061
|
-
model: modelDef.modelName,
|
4062
|
-
entry: sanitizedDocument
|
4063
|
-
});
|
4064
|
-
};
|
4065
4254
|
const documentManager = ({ strapi: strapi2 }) => {
|
4066
4255
|
return {
|
4067
4256
|
async findOne(id, uid2, opts = {}) {
|
@@ -4080,6 +4269,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4080
4269
|
} else if (opts.locale && opts.locale !== "*") {
|
4081
4270
|
where.locale = opts.locale;
|
4082
4271
|
}
|
4272
|
+
if (typeof opts.isPublished === "boolean") {
|
4273
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4274
|
+
}
|
4083
4275
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4084
4276
|
},
|
4085
4277
|
async findMany(opts, uid2) {
|
@@ -4087,20 +4279,16 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4087
4279
|
return strapi2.documents(uid2).findMany(params);
|
4088
4280
|
},
|
4089
4281
|
async findPage(opts, uid2) {
|
4090
|
-
const
|
4091
|
-
|
4282
|
+
const params = strapiUtils.pagination.withDefaultPagination(opts || {}, {
|
4283
|
+
maxLimit: 1e3
|
4284
|
+
});
|
4092
4285
|
const [documents, total = 0] = await Promise.all([
|
4093
|
-
strapi2.documents(uid2).findMany(
|
4094
|
-
strapi2.documents(uid2).count(
|
4286
|
+
strapi2.documents(uid2).findMany(params),
|
4287
|
+
strapi2.documents(uid2).count(params)
|
4095
4288
|
]);
|
4096
4289
|
return {
|
4097
4290
|
results: documents,
|
4098
|
-
pagination:
|
4099
|
-
page,
|
4100
|
-
pageSize,
|
4101
|
-
pageCount: Math.ceil(total / pageSize),
|
4102
|
-
total
|
4103
|
-
}
|
4291
|
+
pagination: strapiUtils.pagination.transformPagedPaginationInfo(params, total)
|
4104
4292
|
};
|
4105
4293
|
},
|
4106
4294
|
async create(uid2, opts = {}) {
|
@@ -4117,10 +4305,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4117
4305
|
async clone(id, body, uid2) {
|
4118
4306
|
const populate = await buildDeepPopulate(uid2);
|
4119
4307
|
const params = {
|
4120
|
-
data:
|
4121
|
-
...omitIdField(body),
|
4122
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4123
|
-
},
|
4308
|
+
data: omitIdField(body),
|
4124
4309
|
populate
|
4125
4310
|
};
|
4126
4311
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4146,70 +4331,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4146
4331
|
return {};
|
4147
4332
|
},
|
4148
4333
|
// FIXME: handle relations
|
4149
|
-
async deleteMany(
|
4150
|
-
const
|
4151
|
-
|
4152
|
-
|
4153
|
-
}
|
4154
|
-
return { count: docs.length };
|
4334
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4335
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4336
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4337
|
+
});
|
4338
|
+
return { count: deletedEntries.length };
|
4155
4339
|
},
|
4156
4340
|
async publish(id, uid2, opts = {}) {
|
4157
4341
|
const populate = await buildDeepPopulate(uid2);
|
4158
4342
|
const params = { ...opts, populate };
|
4159
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4343
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4160
4344
|
},
|
4161
|
-
async publishMany(
|
4162
|
-
|
4163
|
-
|
4164
|
-
|
4165
|
-
|
4166
|
-
|
4167
|
-
|
4168
|
-
strapi2.getModel(uid2),
|
4169
|
-
document,
|
4170
|
-
void 0,
|
4171
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4172
|
-
document
|
4173
|
-
);
|
4174
|
-
})
|
4175
|
-
);
|
4176
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4177
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4178
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4179
|
-
const populate = await buildDeepPopulate(uid2);
|
4180
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4181
|
-
where: filters,
|
4182
|
-
data
|
4183
|
-
});
|
4184
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4185
|
-
where: filters,
|
4186
|
-
populate
|
4345
|
+
async publishMany(uid2, documentIds, locale) {
|
4346
|
+
return strapi2.db.transaction(async () => {
|
4347
|
+
const results = await Promise.all(
|
4348
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4349
|
+
);
|
4350
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4351
|
+
return publishedEntitiesCount;
|
4187
4352
|
});
|
4188
|
-
await Promise.all(
|
4189
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4190
|
-
);
|
4191
|
-
return publishedEntitiesCount;
|
4192
4353
|
},
|
4193
|
-
async unpublishMany(
|
4194
|
-
|
4195
|
-
return
|
4196
|
-
|
4197
|
-
|
4198
|
-
|
4199
|
-
|
4200
|
-
const populate = await buildDeepPopulate(uid2);
|
4201
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4202
|
-
where: filters,
|
4203
|
-
data
|
4204
|
-
});
|
4205
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4206
|
-
where: filters,
|
4207
|
-
populate
|
4354
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4355
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4356
|
+
return Promise.all(
|
4357
|
+
documentIds.map(
|
4358
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4359
|
+
)
|
4360
|
+
);
|
4208
4361
|
});
|
4209
|
-
|
4210
|
-
|
4211
|
-
);
|
4212
|
-
return unpublishedEntitiesCount;
|
4362
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4363
|
+
return { count: unpublishedEntitiesCount };
|
4213
4364
|
},
|
4214
4365
|
async unpublish(id, uid2, opts = {}) {
|
4215
4366
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4234,16 +4385,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4234
4385
|
}
|
4235
4386
|
return sumDraftCounts(document, uid2);
|
4236
4387
|
},
|
4237
|
-
async countManyEntriesDraftRelations(
|
4388
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4238
4389
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4239
4390
|
if (!hasRelations) {
|
4240
4391
|
return 0;
|
4241
4392
|
}
|
4393
|
+
let localeFilter = {};
|
4394
|
+
if (locale) {
|
4395
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4396
|
+
}
|
4242
4397
|
const entities = await strapi2.db.query(uid2).findMany({
|
4243
4398
|
populate,
|
4244
4399
|
where: {
|
4245
|
-
|
4246
|
-
...
|
4400
|
+
documentId: { $in: documentIds },
|
4401
|
+
...localeFilter
|
4247
4402
|
}
|
4248
4403
|
});
|
4249
4404
|
const totalNumberDraftRelations = entities.reduce(
|