@strapi/content-manager 0.0.0-experimental.32c4b04580cc12400710050c8198e46b3644cfd4 → 0.0.0-experimental.332a7d5b6b1d23635d7e205657f0ff39ec133c9e
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/CardDragPreview-C0QyJgRA.js.map +1 -1
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs → ComponentConfigurationPage-D4H-v0et.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-D4H-v0et.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-DdkVGfXC.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-DdkVGfXC.js.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
- package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
- package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-D1nvB7Br.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-D1nvB7Br.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-LYEvR4fW.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-LYEvR4fW.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-Bcnff6Vd.mjs} +34 -46
- package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-DqelJ9UK.js} +36 -49
- package/dist/_chunks/EditViewPage-DqelJ9UK.js.map +1 -0
- package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
- package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
- package/dist/_chunks/{Form-CPYqIWDG.js → Form-CnHfBeiB.js} +39 -21
- package/dist/_chunks/Form-CnHfBeiB.js.map +1 -0
- package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-CzPCJi3B.mjs} +37 -18
- package/dist/_chunks/Form-CzPCJi3B.mjs.map +1 -0
- package/dist/_chunks/{History-wrnHqf09.mjs → History-CcmSn3Mj.mjs} +71 -104
- package/dist/_chunks/History-CcmSn3Mj.mjs.map +1 -0
- package/dist/_chunks/{History-DNQkXANT.js → History-zArjENzj.js} +81 -115
- package/dist/_chunks/History-zArjENzj.js.map +1 -0
- package/dist/_chunks/{Field-Bfph5SOd.js → Input-CDHKQd7o.js} +1334 -1239
- package/dist/_chunks/Input-CDHKQd7o.js.map +1 -0
- package/dist/_chunks/{Field-Cs7duwWd.mjs → Input-aV8SSoTa.mjs} +1192 -1097
- package/dist/_chunks/Input-aV8SSoTa.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-BPvzENJJ.mjs} +19 -8
- package/dist/_chunks/ListConfigurationPage-BPvzENJJ.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-ByZAO_9H.js} +19 -9
- package/dist/_chunks/ListConfigurationPage-ByZAO_9H.js.map +1 -0
- package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-BVKBeQAA.js} +108 -74
- package/dist/_chunks/ListViewPage-BVKBeQAA.js.map +1 -0
- package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-HljQVnFH.mjs} +109 -74
- package/dist/_chunks/ListViewPage-HljQVnFH.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-BV5zfDxr.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-BV5zfDxr.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-BfHaSM-K.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-BfHaSM-K.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-D6ze2nQL.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-D6ze2nQL.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-vdNpc6jb.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-vdNpc6jb.js.map} +1 -1
- package/dist/_chunks/Preview-DEHdENT1.js +305 -0
- package/dist/_chunks/Preview-DEHdENT1.js.map +1 -0
- package/dist/_chunks/Preview-vfWOtPG5.mjs +287 -0
- package/dist/_chunks/Preview-vfWOtPG5.mjs.map +1 -0
- package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-B7_hbF0w.mjs} +79 -44
- package/dist/_chunks/Relations-B7_hbF0w.mjs.map +1 -0
- package/dist/_chunks/{Relations-CtELXYIK.js → Relations-DcoOBejP.js} +79 -45
- package/dist/_chunks/Relations-DcoOBejP.js.map +1 -0
- package/dist/_chunks/{en-uOUIxfcQ.js → en-BR48D_RH.js} +35 -15
- package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BR48D_RH.js.map} +1 -1
- package/dist/_chunks/{en-BrCTWlZv.mjs → en-D65uIF6Y.mjs} +35 -15
- package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
- package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
- package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
- package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
- package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-OerGjbAN.js → index-CxLSGwnk.js} +1304 -750
- package/dist/_chunks/index-CxLSGwnk.js.map +1 -0
- package/dist/_chunks/{index-c_5DdJi-.mjs → index-EH8ZtHd5.mjs} +1323 -769
- package/dist/_chunks/index-EH8ZtHd5.mjs.map +1 -0
- package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
- package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
- package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
- package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
- package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-CxDMdJ13.mjs} +23 -10
- package/dist/_chunks/layout-CxDMdJ13.mjs.map +1 -0
- package/dist/_chunks/{layout-Ci7qHlFb.js → layout-DSeUTfMv.js} +23 -11
- package/dist/_chunks/layout-DSeUTfMv.js.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-B8_Uu38Q.mjs} +21 -8
- package/dist/_chunks/relations-B8_Uu38Q.mjs.map +1 -0
- package/dist/_chunks/{relations-COBpStiF.js → relations-S5nNKdN3.js} +20 -7
- package/dist/_chunks/relations-S5nNKdN3.js.map +1 -0
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -1
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +6 -4
- package/dist/admin/src/content-manager.d.ts +3 -2
- package/dist/admin/src/exports.d.ts +2 -1
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +49 -1
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.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 +4 -48
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
- package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
- package/dist/admin/src/preview/index.d.ts +4 -0
- package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
- package/dist/admin/src/preview/routes.d.ts +3 -0
- package/dist/admin/src/preview/services/preview.d.ts +3 -0
- package/dist/admin/src/router.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -20
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +727 -406
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +728 -406
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts +3 -3
- 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 +8 -12
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +7 -6
- 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/preview/controllers/index.d.ts +2 -0
- package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/preview.d.ts +13 -0
- package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
- package/dist/server/src/preview/index.d.ts +4 -0
- package/dist/server/src/preview/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/index.d.ts +8 -0
- package/dist/server/src/preview/routes/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/preview.d.ts +4 -0
- package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
- package/dist/server/src/preview/services/index.d.ts +16 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts +32 -0
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview.d.ts +12 -0
- package/dist/server/src/preview/services/preview.d.ts.map +1 -0
- package/dist/server/src/preview/utils.d.ts +19 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +12 -10
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +7 -6
- 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 +2 -2
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/index.d.ts +1 -0
- package/dist/shared/contracts/index.d.ts.map +1 -1
- package/dist/shared/contracts/preview.d.ts +27 -0
- package/dist/shared/contracts/preview.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +4 -0
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +17 -16
- package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
- package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
- package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
- package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
- package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
- package/dist/_chunks/History-DNQkXANT.js.map +0 -1
- package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
- package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
- package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
- package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
- package/dist/_chunks/index-OerGjbAN.js.map +0 -1
- package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
- package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
- package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
- package/dist/_chunks/relations-BIdWFjdq.mjs.map +0 -1
- package/dist/_chunks/relations-COBpStiF.js.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1,
|
2
|
-
import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat,
|
1
|
+
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, traverseEntity, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, pagination } from "@strapi/utils";
|
2
|
+
import { pick, omit, difference, castArray, mergeWith, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
|
3
3
|
import "@strapi/types";
|
4
4
|
import * as yup from "yup";
|
5
5
|
import { scheduleJob } from "node-schedule";
|
@@ -7,10 +7,10 @@ import isNil from "lodash/isNil";
|
|
7
7
|
import _, { intersection as intersection$1, difference as difference$1 } from "lodash";
|
8
8
|
import qs from "qs";
|
9
9
|
import slugify from "@sindresorhus/slugify";
|
10
|
-
const getService$
|
10
|
+
const getService$2 = (name) => {
|
11
11
|
return strapi.plugin("content-manager").service(name);
|
12
12
|
};
|
13
|
-
function getService(strapi2, name) {
|
13
|
+
function getService$1(strapi2, name) {
|
14
14
|
return strapi2.service(`plugin::content-manager.${name}`);
|
15
15
|
}
|
16
16
|
const historyRestoreVersionSchema = yup.object().shape({
|
@@ -46,7 +46,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
46
46
|
if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
|
47
47
|
throw new errors.ForbiddenError("contentType and documentId are required");
|
48
48
|
}
|
49
|
-
const permissionChecker2 = getService$
|
49
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
50
50
|
userAbility: ctx.state.userAbility,
|
51
51
|
model: ctx.query.contentType
|
52
52
|
});
|
@@ -54,7 +54,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
54
54
|
return ctx.forbidden();
|
55
55
|
}
|
56
56
|
const query = await permissionChecker2.sanitizeQuery(ctx.query);
|
57
|
-
const { results, pagination: pagination2 } = await getService(strapi2, "history").findVersionsPage({
|
57
|
+
const { results, pagination: pagination2 } = await getService$1(strapi2, "history").findVersionsPage({
|
58
58
|
query: {
|
59
59
|
...query,
|
60
60
|
...getValidPagination({ page: query.page, pageSize: query.pageSize })
|
@@ -79,14 +79,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
79
79
|
async restoreVersion(ctx) {
|
80
80
|
const request = ctx.request;
|
81
81
|
await validateRestoreVersion(request.body, "contentType is required");
|
82
|
-
const permissionChecker2 = getService$
|
82
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
83
83
|
userAbility: ctx.state.userAbility,
|
84
84
|
model: request.body.contentType
|
85
85
|
});
|
86
86
|
if (permissionChecker2.cannot.update()) {
|
87
87
|
throw new errors.ForbiddenError();
|
88
88
|
}
|
89
|
-
const restoredDocument = await getService(strapi2, "history").restoreVersion(
|
89
|
+
const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
|
90
90
|
request.params.versionId
|
91
91
|
);
|
92
92
|
return {
|
@@ -95,7 +95,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
95
95
|
}
|
96
96
|
};
|
97
97
|
};
|
98
|
-
const controllers$
|
98
|
+
const controllers$2 = {
|
99
99
|
"history-version": createHistoryVersionController
|
100
100
|
/**
|
101
101
|
* Casting is needed because the types aren't aware that Strapi supports
|
@@ -141,8 +141,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
141
141
|
};
|
142
142
|
const getRelationRestoreValue = async (versionRelationData, attribute) => {
|
143
143
|
if (Array.isArray(versionRelationData)) {
|
144
|
-
if (versionRelationData.length === 0)
|
145
|
-
return versionRelationData;
|
144
|
+
if (versionRelationData.length === 0) return versionRelationData;
|
146
145
|
const existingAndMissingRelations = await Promise.all(
|
147
146
|
versionRelationData.map((relation) => {
|
148
147
|
return strapi2.documents(attribute.target).findOne({
|
@@ -151,19 +150,16 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
151
150
|
});
|
152
151
|
})
|
153
152
|
);
|
154
|
-
return existingAndMissingRelations.filter(
|
155
|
-
(relation) => relation !== null
|
156
|
-
);
|
153
|
+
return existingAndMissingRelations.filter((relation) => relation !== null);
|
157
154
|
}
|
158
155
|
return strapi2.documents(attribute.target).findOne({
|
159
156
|
documentId: versionRelationData.documentId,
|
160
157
|
locale: versionRelationData.locale || void 0
|
161
158
|
});
|
162
159
|
};
|
163
|
-
const getMediaRestoreValue = async (versionRelationData
|
164
|
-
if (
|
160
|
+
const getMediaRestoreValue = async (versionRelationData) => {
|
161
|
+
if (Array.isArray(versionRelationData)) {
|
165
162
|
const existingAndMissingMedias = await Promise.all(
|
166
|
-
// @ts-expect-error Fix the type definitions so this isn't any
|
167
163
|
versionRelationData.map((media) => {
|
168
164
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
|
169
165
|
})
|
@@ -173,10 +169,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
173
169
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
174
170
|
};
|
175
171
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
172
|
+
const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
|
176
173
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
174
|
+
const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
|
177
175
|
const getLocaleDictionary = async () => {
|
178
|
-
if (!localesService)
|
179
|
-
return {};
|
176
|
+
if (!localesService) return {};
|
180
177
|
const locales = await localesService.find() || [];
|
181
178
|
return locales.reduce(
|
182
179
|
(acc, locale) => {
|
@@ -200,9 +197,21 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
200
197
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
201
198
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
202
199
|
};
|
203
|
-
const
|
200
|
+
const getComponentFields = (componentUID) => {
|
201
|
+
return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
|
202
|
+
(fieldsAcc, [key, attribute]) => {
|
203
|
+
if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
|
204
|
+
fieldsAcc.push(key);
|
205
|
+
}
|
206
|
+
return fieldsAcc;
|
207
|
+
},
|
208
|
+
[]
|
209
|
+
);
|
210
|
+
};
|
211
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
204
212
|
const model = strapi2.getModel(uid2);
|
205
213
|
const attributes = Object.entries(model.attributes);
|
214
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
206
215
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
207
216
|
switch (attribute.type) {
|
208
217
|
case "relation": {
|
@@ -212,23 +221,29 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
212
221
|
}
|
213
222
|
const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
|
214
223
|
if (isVisible2) {
|
215
|
-
acc[attributeName] = {
|
224
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
216
225
|
}
|
217
226
|
break;
|
218
227
|
}
|
219
228
|
case "media": {
|
220
|
-
acc[attributeName] = {
|
229
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
221
230
|
break;
|
222
231
|
}
|
223
232
|
case "component": {
|
224
233
|
const populate = getDeepPopulate2(attribute.component);
|
225
|
-
acc[attributeName] = {
|
234
|
+
acc[attributeName] = {
|
235
|
+
populate,
|
236
|
+
[fieldSelector]: getComponentFields(attribute.component)
|
237
|
+
};
|
226
238
|
break;
|
227
239
|
}
|
228
240
|
case "dynamiczone": {
|
229
241
|
const populatedComponents = (attribute.components || []).reduce(
|
230
242
|
(acc2, componentUID) => {
|
231
|
-
acc2[componentUID] = {
|
243
|
+
acc2[componentUID] = {
|
244
|
+
populate: getDeepPopulate2(componentUID),
|
245
|
+
[fieldSelector]: getComponentFields(componentUID)
|
246
|
+
};
|
232
247
|
return acc2;
|
233
248
|
},
|
234
249
|
{}
|
@@ -290,6 +305,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
290
305
|
getRelationRestoreValue,
|
291
306
|
getMediaRestoreValue,
|
292
307
|
getDefaultLocale,
|
308
|
+
isLocalizedContentType,
|
293
309
|
getLocaleDictionary,
|
294
310
|
getRetentionDays,
|
295
311
|
getVersionStatus,
|
@@ -312,7 +328,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
312
328
|
});
|
313
329
|
},
|
314
330
|
async findVersionsPage(params) {
|
315
|
-
const
|
331
|
+
const schema = strapi2.getModel(params.query.contentType);
|
332
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(schema);
|
333
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
334
|
+
let locale = null;
|
335
|
+
if (isLocalizedContentType) {
|
336
|
+
locale = params.query.locale || defaultLocale;
|
337
|
+
}
|
316
338
|
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
317
339
|
query.findPage({
|
318
340
|
...params.query,
|
@@ -328,78 +350,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
328
350
|
}),
|
329
351
|
serviceUtils.getLocaleDictionary()
|
330
352
|
]);
|
331
|
-
const
|
332
|
-
|
333
|
-
async (
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
model: "plugin::upload.file"
|
340
|
-
});
|
341
|
-
const response = await serviceUtils.buildMediaResponse(attributeValues);
|
342
|
-
const sanitizedResults = await Promise.all(
|
343
|
-
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
344
|
-
);
|
345
|
-
return {
|
346
|
-
...await currentDataWithRelations,
|
347
|
-
[attributeKey]: {
|
348
|
-
results: sanitizedResults,
|
349
|
-
meta: response.meta
|
350
|
-
}
|
351
|
-
};
|
353
|
+
const populateEntry = async (entry) => {
|
354
|
+
return traverseEntity(
|
355
|
+
async (options, utils) => {
|
356
|
+
if (!options.attribute) return;
|
357
|
+
if (!options.value) return;
|
358
|
+
const currentValue = Array.isArray(options.value) ? options.value : [options.value];
|
359
|
+
if (options.attribute.type === "component") {
|
360
|
+
utils.remove("id");
|
352
361
|
}
|
353
|
-
if (
|
354
|
-
|
362
|
+
if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
|
363
|
+
options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
|
364
|
+
if (options.attribute.target === "admin::user") {
|
355
365
|
const adminUsers = await Promise.all(
|
356
|
-
|
366
|
+
currentValue.map((userToPopulate) => {
|
357
367
|
if (userToPopulate == null) {
|
358
368
|
return null;
|
359
369
|
}
|
360
|
-
return strapi2.query("admin::user").findOne({
|
370
|
+
return strapi2.query("admin::user").findOne({
|
371
|
+
where: {
|
372
|
+
...userToPopulate.id ? { id: userToPopulate.id } : {},
|
373
|
+
...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
|
374
|
+
}
|
375
|
+
});
|
361
376
|
})
|
362
377
|
);
|
363
|
-
|
364
|
-
...await currentDataWithRelations,
|
365
|
-
/**
|
366
|
-
* Ideally we would return the same "{results: [], meta: {}}" shape, however,
|
367
|
-
* when sanitizing the data as a whole in the controller before sending to the client,
|
368
|
-
* the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
|
369
|
-
*/
|
370
|
-
[attributeKey]: adminUsers
|
371
|
-
};
|
378
|
+
utils.set(options.key, adminUsers);
|
372
379
|
}
|
373
|
-
const permissionChecker2 = getService$
|
380
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
374
381
|
userAbility: params.state.userAbility,
|
375
|
-
model:
|
382
|
+
model: options.attribute.target
|
376
383
|
});
|
377
384
|
const response = await serviceUtils.buildRelationReponse(
|
378
|
-
|
379
|
-
|
385
|
+
currentValue,
|
386
|
+
options.attribute
|
380
387
|
);
|
381
388
|
const sanitizedResults = await Promise.all(
|
382
389
|
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
383
390
|
);
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
meta: response.meta
|
389
|
-
}
|
390
|
-
};
|
391
|
+
utils.set(options.key, {
|
392
|
+
results: sanitizedResults,
|
393
|
+
meta: response.meta
|
394
|
+
});
|
391
395
|
}
|
392
|
-
|
396
|
+
if (options.attribute.type === "media") {
|
397
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
398
|
+
userAbility: params.state.userAbility,
|
399
|
+
model: "plugin::upload.file"
|
400
|
+
});
|
401
|
+
const response = await serviceUtils.buildMediaResponse(currentValue);
|
402
|
+
const sanitizedResults = await Promise.all(
|
403
|
+
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
404
|
+
);
|
405
|
+
utils.set(options.key, {
|
406
|
+
results: sanitizedResults,
|
407
|
+
meta: response.meta
|
408
|
+
});
|
409
|
+
}
|
410
|
+
},
|
411
|
+
{
|
412
|
+
schema,
|
413
|
+
getModel: strapi2.getModel.bind(strapi2)
|
393
414
|
},
|
394
|
-
|
415
|
+
entry.data
|
395
416
|
);
|
396
|
-
return entryWithRelations;
|
397
417
|
};
|
398
418
|
const formattedResults = await Promise.all(
|
399
419
|
results.map(async (result) => {
|
400
420
|
return {
|
401
421
|
...result,
|
402
|
-
data: await
|
422
|
+
data: await populateEntry(result),
|
403
423
|
meta: {
|
404
424
|
unknownAttributes: serviceUtils.getSchemaAttributesDiff(
|
405
425
|
result.schema,
|
@@ -430,30 +450,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
430
450
|
// Clone to avoid mutating the original version data
|
431
451
|
structuredClone(version.data)
|
432
452
|
);
|
433
|
-
const
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
453
|
+
const schema = structuredClone(version.schema);
|
454
|
+
schema.attributes = omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
|
455
|
+
const dataWithoutMissingRelations = await traverseEntity(
|
456
|
+
async (options, utils) => {
|
457
|
+
if (!options.attribute) return;
|
458
|
+
if (options.attribute.type === "component") {
|
459
|
+
utils.remove("id");
|
460
|
+
if (options.attribute.repeatable && options.value === null) {
|
461
|
+
utils.set(options.key, []);
|
462
|
+
}
|
463
|
+
}
|
464
|
+
if (options.attribute.type === "dynamiczone") {
|
465
|
+
if (options.value === null) {
|
466
|
+
utils.set(options.key, []);
|
467
|
+
}
|
443
468
|
}
|
444
|
-
if (attribute.type === "relation" && // TODO: handle polymorphic relations
|
445
|
-
attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
|
446
|
-
|
447
|
-
|
469
|
+
if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
|
470
|
+
options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
|
471
|
+
if (!options.value) return;
|
472
|
+
const data2 = await serviceUtils.getRelationRestoreValue(
|
473
|
+
options.value,
|
474
|
+
options.attribute
|
475
|
+
);
|
476
|
+
utils.set(options.key, data2);
|
448
477
|
}
|
449
|
-
if (attribute.type === "media") {
|
450
|
-
|
451
|
-
|
478
|
+
if (options.attribute.type === "media") {
|
479
|
+
if (!options.value) return;
|
480
|
+
const data2 = await serviceUtils.getMediaRestoreValue(
|
481
|
+
options.value
|
482
|
+
);
|
483
|
+
utils.set(options.key, data2);
|
452
484
|
}
|
453
|
-
return previousRelationAttributes;
|
454
485
|
},
|
455
|
-
|
456
|
-
|
486
|
+
{
|
487
|
+
schema,
|
488
|
+
getModel: strapi2.getModel.bind(strapi2)
|
489
|
+
},
|
490
|
+
dataWithoutAddedAttributes
|
457
491
|
);
|
458
492
|
const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
|
459
493
|
const restoredDocument = await strapi2.documents(version.contentType).update({
|
@@ -468,6 +502,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
468
502
|
}
|
469
503
|
};
|
470
504
|
};
|
505
|
+
const shouldCreateHistoryVersion = (context) => {
|
506
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
507
|
+
return false;
|
508
|
+
}
|
509
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
510
|
+
return false;
|
511
|
+
}
|
512
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
513
|
+
return false;
|
514
|
+
}
|
515
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
516
|
+
return false;
|
517
|
+
}
|
518
|
+
return true;
|
519
|
+
};
|
520
|
+
const getSchemas = (uid2) => {
|
521
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
522
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
523
|
+
(currentComponentSchemas, key) => {
|
524
|
+
const fieldSchema = attributesSchema[key];
|
525
|
+
if (fieldSchema.type === "component") {
|
526
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
527
|
+
return {
|
528
|
+
...currentComponentSchemas,
|
529
|
+
[fieldSchema.component]: componentSchema
|
530
|
+
};
|
531
|
+
}
|
532
|
+
return currentComponentSchemas;
|
533
|
+
},
|
534
|
+
{}
|
535
|
+
);
|
536
|
+
return {
|
537
|
+
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
538
|
+
componentsSchemas
|
539
|
+
};
|
540
|
+
};
|
471
541
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
472
542
|
const state = {
|
473
543
|
deleteExpiredJob: null,
|
@@ -480,76 +550,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
480
550
|
return;
|
481
551
|
}
|
482
552
|
strapi2.documents.use(async (context, next) => {
|
483
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
484
|
-
return next();
|
485
|
-
}
|
486
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
487
|
-
return next();
|
488
|
-
}
|
489
|
-
if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
490
|
-
return next();
|
491
|
-
}
|
492
|
-
const contentTypeUid = context.contentType.uid;
|
493
|
-
if (!contentTypeUid.startsWith("api::")) {
|
494
|
-
return next();
|
495
|
-
}
|
496
553
|
const result = await next();
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
554
|
+
if (!shouldCreateHistoryVersion(context)) {
|
555
|
+
return result;
|
556
|
+
}
|
557
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
501
558
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
502
|
-
const
|
503
|
-
if (
|
504
|
-
|
505
|
-
"[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
|
506
|
-
);
|
507
|
-
return next();
|
559
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
560
|
+
if (!locales.length) {
|
561
|
+
return result;
|
508
562
|
}
|
509
|
-
const
|
510
|
-
|
511
|
-
|
512
|
-
|
563
|
+
const uid2 = context.contentType.uid;
|
564
|
+
const schemas = getSchemas(uid2);
|
565
|
+
const model = strapi2.getModel(uid2);
|
566
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
567
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
568
|
+
where: {
|
569
|
+
documentId,
|
570
|
+
...isLocalizedContentType ? { locale: { $in: locales } } : {},
|
571
|
+
...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
|
572
|
+
},
|
573
|
+
populate: serviceUtils.getDeepPopulate(
|
574
|
+
uid2,
|
575
|
+
true
|
576
|
+
/* use database syntax */
|
577
|
+
)
|
513
578
|
});
|
514
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
515
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
516
|
-
const componentsSchemas = Object.keys(
|
517
|
-
attributesSchema
|
518
|
-
).reduce((currentComponentSchemas, key) => {
|
519
|
-
const fieldSchema = attributesSchema[key];
|
520
|
-
if (fieldSchema.type === "component") {
|
521
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
522
|
-
return {
|
523
|
-
...currentComponentSchemas,
|
524
|
-
[fieldSchema.component]: componentSchema
|
525
|
-
};
|
526
|
-
}
|
527
|
-
return currentComponentSchemas;
|
528
|
-
}, {});
|
529
579
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
530
|
-
onCommit(() => {
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
580
|
+
onCommit(async () => {
|
581
|
+
for (const entry of localeEntries) {
|
582
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
583
|
+
await getService$1(strapi2, "history").createVersion({
|
584
|
+
contentType: uid2,
|
585
|
+
data: omit(FIELDS_TO_IGNORE, entry),
|
586
|
+
relatedDocumentId: documentId,
|
587
|
+
locale: entry.locale,
|
588
|
+
status,
|
589
|
+
...schemas
|
590
|
+
});
|
591
|
+
}
|
540
592
|
});
|
541
593
|
});
|
542
594
|
return result;
|
543
595
|
});
|
544
|
-
state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
|
596
|
+
state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
|
545
597
|
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
546
598
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
547
599
|
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
548
600
|
where: {
|
549
601
|
created_at: {
|
550
|
-
$lt: expirationDate
|
602
|
+
$lt: expirationDate
|
551
603
|
}
|
552
604
|
}
|
605
|
+
}).catch((error) => {
|
606
|
+
if (error instanceof Error) {
|
607
|
+
strapi2.log.error("Error deleting expired history versions", error.message);
|
608
|
+
}
|
553
609
|
});
|
554
610
|
});
|
555
611
|
state.isInitialized = true;
|
@@ -561,17 +617,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
561
617
|
}
|
562
618
|
};
|
563
619
|
};
|
564
|
-
const services$
|
620
|
+
const services$2 = {
|
565
621
|
history: createHistoryService,
|
566
622
|
lifecycles: createLifecyclesService
|
567
623
|
};
|
568
|
-
const info = { pluginName: "content-manager", type: "admin" };
|
624
|
+
const info$1 = { pluginName: "content-manager", type: "admin" };
|
569
625
|
const historyVersionRouter = {
|
570
626
|
type: "admin",
|
571
627
|
routes: [
|
572
628
|
{
|
573
629
|
method: "GET",
|
574
|
-
info,
|
630
|
+
info: info$1,
|
575
631
|
path: "/history-versions",
|
576
632
|
handler: "history-version.findMany",
|
577
633
|
config: {
|
@@ -580,7 +636,7 @@ const historyVersionRouter = {
|
|
580
636
|
},
|
581
637
|
{
|
582
638
|
method: "PUT",
|
583
|
-
info,
|
639
|
+
info: info$1,
|
584
640
|
path: "/history-versions/:versionId/restore",
|
585
641
|
handler: "history-version.restoreVersion",
|
586
642
|
config: {
|
@@ -589,7 +645,7 @@ const historyVersionRouter = {
|
|
589
645
|
}
|
590
646
|
]
|
591
647
|
};
|
592
|
-
const routes$
|
648
|
+
const routes$2 = {
|
593
649
|
"history-version": historyVersionRouter
|
594
650
|
};
|
595
651
|
const historyVersion = {
|
@@ -636,21 +692,21 @@ const historyVersion = {
|
|
636
692
|
}
|
637
693
|
}
|
638
694
|
};
|
639
|
-
const getFeature = () => {
|
695
|
+
const getFeature$1 = () => {
|
640
696
|
if (strapi.ee.features.isEnabled("cms-content-history")) {
|
641
697
|
return {
|
642
698
|
register({ strapi: strapi2 }) {
|
643
699
|
strapi2.get("models").add(historyVersion);
|
644
700
|
},
|
645
701
|
bootstrap({ strapi: strapi2 }) {
|
646
|
-
getService(strapi2, "lifecycles").bootstrap();
|
702
|
+
getService$1(strapi2, "lifecycles").bootstrap();
|
647
703
|
},
|
648
704
|
destroy({ strapi: strapi2 }) {
|
649
|
-
getService(strapi2, "lifecycles").destroy();
|
705
|
+
getService$1(strapi2, "lifecycles").destroy();
|
650
706
|
},
|
651
|
-
controllers: controllers$
|
652
|
-
services: services$
|
653
|
-
routes: routes$
|
707
|
+
controllers: controllers$2,
|
708
|
+
services: services$2,
|
709
|
+
routes: routes$2
|
654
710
|
};
|
655
711
|
}
|
656
712
|
return {
|
@@ -659,9 +715,201 @@ const getFeature = () => {
|
|
659
715
|
}
|
660
716
|
};
|
661
717
|
};
|
662
|
-
const history = getFeature();
|
718
|
+
const history = getFeature$1();
|
719
|
+
const info = { pluginName: "content-manager", type: "admin" };
|
720
|
+
const previewRouter = {
|
721
|
+
type: "admin",
|
722
|
+
routes: [
|
723
|
+
{
|
724
|
+
method: "GET",
|
725
|
+
info,
|
726
|
+
path: "/preview/url/:contentType",
|
727
|
+
handler: "preview.getPreviewUrl",
|
728
|
+
config: {
|
729
|
+
policies: ["admin::isAuthenticatedAdmin"]
|
730
|
+
}
|
731
|
+
}
|
732
|
+
]
|
733
|
+
};
|
734
|
+
const routes$1 = {
|
735
|
+
preview: previewRouter
|
736
|
+
};
|
737
|
+
function getService(strapi2, name) {
|
738
|
+
return strapi2.service(`plugin::content-manager.${name}`);
|
739
|
+
}
|
740
|
+
const getPreviewUrlSchema = yup.object().shape({
|
741
|
+
// Will be undefined for single types
|
742
|
+
documentId: yup.string(),
|
743
|
+
locale: yup.string().nullable(),
|
744
|
+
status: yup.string()
|
745
|
+
}).required();
|
746
|
+
const validatePreviewUrl = async (strapi2, uid2, params) => {
|
747
|
+
await validateYupSchema(getPreviewUrlSchema)(params);
|
748
|
+
const newParams = pick(["documentId", "locale", "status"], params);
|
749
|
+
const model = strapi2.getModel(uid2);
|
750
|
+
if (!model || model.modelType !== "contentType") {
|
751
|
+
throw new errors.ValidationError("Invalid content type");
|
752
|
+
}
|
753
|
+
const isSingleType = model?.kind === "singleType";
|
754
|
+
if (!isSingleType && !params.documentId) {
|
755
|
+
throw new errors.ValidationError("documentId is required for Collection Types");
|
756
|
+
}
|
757
|
+
if (isSingleType) {
|
758
|
+
const doc = await strapi2.documents(uid2).findFirst();
|
759
|
+
if (!doc) {
|
760
|
+
throw new errors.NotFoundError("Document not found");
|
761
|
+
}
|
762
|
+
newParams.documentId = doc?.documentId;
|
763
|
+
}
|
764
|
+
if (!newParams.status) {
|
765
|
+
const isDPEnabled = model?.options?.draftAndPublish;
|
766
|
+
newParams.status = isDPEnabled ? "draft" : "published";
|
767
|
+
}
|
768
|
+
return newParams;
|
769
|
+
};
|
770
|
+
const createPreviewController = () => {
|
771
|
+
return {
|
772
|
+
/**
|
773
|
+
* Transforms an entry into a preview URL, so that it can be previewed
|
774
|
+
* in the Content Manager.
|
775
|
+
*/
|
776
|
+
async getPreviewUrl(ctx) {
|
777
|
+
const uid2 = ctx.params.contentType;
|
778
|
+
const query = ctx.request.query;
|
779
|
+
const params = await validatePreviewUrl(strapi, uid2, query);
|
780
|
+
const previewService = getService(strapi, "preview");
|
781
|
+
const url = await previewService.getPreviewUrl(uid2, params);
|
782
|
+
if (!url) {
|
783
|
+
ctx.status = 204;
|
784
|
+
}
|
785
|
+
return {
|
786
|
+
data: { url }
|
787
|
+
};
|
788
|
+
}
|
789
|
+
};
|
790
|
+
};
|
791
|
+
const controllers$1 = {
|
792
|
+
preview: createPreviewController
|
793
|
+
/**
|
794
|
+
* Casting is needed because the types aren't aware that Strapi supports
|
795
|
+
* passing a controller factory as the value, instead of a controller object directly
|
796
|
+
*/
|
797
|
+
};
|
798
|
+
const createPreviewService = ({ strapi: strapi2 }) => {
|
799
|
+
const config = getService(strapi2, "preview-config");
|
800
|
+
return {
|
801
|
+
async getPreviewUrl(uid2, params) {
|
802
|
+
const handler = config.getPreviewHandler();
|
803
|
+
try {
|
804
|
+
return handler(uid2, params);
|
805
|
+
} catch (error) {
|
806
|
+
strapi2.log.error(`Failed to get preview URL: ${error}`);
|
807
|
+
throw new errors.ApplicationError("Failed to get preview URL");
|
808
|
+
}
|
809
|
+
return;
|
810
|
+
}
|
811
|
+
};
|
812
|
+
};
|
813
|
+
const extendMiddlewareConfiguration = (middleware = { name: "", config: {} }) => {
|
814
|
+
const middlewares = strapi.config.get("middlewares");
|
815
|
+
const configuredMiddlewares = middlewares.map((currentMiddleware) => {
|
816
|
+
if (currentMiddleware === middleware.name) {
|
817
|
+
return middleware;
|
818
|
+
}
|
819
|
+
if (currentMiddleware.name === middleware.name) {
|
820
|
+
return mergeWith(
|
821
|
+
(objValue, srcValue) => {
|
822
|
+
if (Array.isArray(objValue)) {
|
823
|
+
return objValue.concat(srcValue);
|
824
|
+
}
|
825
|
+
return void 0;
|
826
|
+
},
|
827
|
+
currentMiddleware,
|
828
|
+
middleware
|
829
|
+
);
|
830
|
+
}
|
831
|
+
return currentMiddleware;
|
832
|
+
});
|
833
|
+
strapi.config.set("middlewares", configuredMiddlewares);
|
834
|
+
};
|
835
|
+
const createPreviewConfigService = ({ strapi: strapi2 }) => {
|
836
|
+
return {
|
837
|
+
register() {
|
838
|
+
if (!this.isEnabled()) {
|
839
|
+
return;
|
840
|
+
}
|
841
|
+
const config = strapi2.config.get("admin.preview");
|
842
|
+
if (config.config?.allowedOrigins) {
|
843
|
+
extendMiddlewareConfiguration({
|
844
|
+
name: "strapi::security",
|
845
|
+
config: {
|
846
|
+
contentSecurityPolicy: {
|
847
|
+
directives: {
|
848
|
+
"frame-src": config.config.allowedOrigins
|
849
|
+
}
|
850
|
+
}
|
851
|
+
}
|
852
|
+
});
|
853
|
+
}
|
854
|
+
},
|
855
|
+
isEnabled() {
|
856
|
+
const config = strapi2.config.get("admin.preview");
|
857
|
+
if (!config) {
|
858
|
+
return false;
|
859
|
+
}
|
860
|
+
return config?.enabled ?? true;
|
861
|
+
},
|
862
|
+
/**
|
863
|
+
* Validate if the configuration is valid
|
864
|
+
*/
|
865
|
+
validate() {
|
866
|
+
if (!this.isEnabled()) {
|
867
|
+
return;
|
868
|
+
}
|
869
|
+
const handler = this.getPreviewHandler();
|
870
|
+
if (typeof handler !== "function") {
|
871
|
+
throw new errors.ValidationError(
|
872
|
+
"Preview configuration is invalid. Handler must be a function"
|
873
|
+
);
|
874
|
+
}
|
875
|
+
},
|
876
|
+
/**
|
877
|
+
* Utility to get the preview handler from the configuration
|
878
|
+
*/
|
879
|
+
getPreviewHandler() {
|
880
|
+
const config = strapi2.config.get("admin.preview");
|
881
|
+
const emptyHandler = () => {
|
882
|
+
return void 0;
|
883
|
+
};
|
884
|
+
if (!this.isEnabled()) {
|
885
|
+
return emptyHandler;
|
886
|
+
}
|
887
|
+
return config?.config?.handler || emptyHandler;
|
888
|
+
}
|
889
|
+
};
|
890
|
+
};
|
891
|
+
const services$1 = {
|
892
|
+
preview: createPreviewService,
|
893
|
+
"preview-config": createPreviewConfigService
|
894
|
+
};
|
895
|
+
const getFeature = () => {
|
896
|
+
return {
|
897
|
+
register() {
|
898
|
+
const config = getService(strapi, "preview-config");
|
899
|
+
config.validate();
|
900
|
+
config.register();
|
901
|
+
},
|
902
|
+
bootstrap() {
|
903
|
+
},
|
904
|
+
routes: routes$1,
|
905
|
+
controllers: controllers$1,
|
906
|
+
services: services$1
|
907
|
+
};
|
908
|
+
};
|
909
|
+
const preview = getFeature();
|
663
910
|
const register = async ({ strapi: strapi2 }) => {
|
664
911
|
await history.register?.({ strapi: strapi2 });
|
912
|
+
await preview.register?.({ strapi: strapi2 });
|
665
913
|
};
|
666
914
|
const ALLOWED_WEBHOOK_EVENTS = {
|
667
915
|
ENTRY_PUBLISH: "entry.publish",
|
@@ -671,11 +919,12 @@ const bootstrap = async () => {
|
|
671
919
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
672
920
|
strapi.get("webhookStore").addAllowedEvent(key, value);
|
673
921
|
});
|
674
|
-
getService$
|
675
|
-
await getService$
|
676
|
-
await getService$
|
677
|
-
await getService$
|
922
|
+
getService$2("field-sizes").setCustomFieldInputSizes();
|
923
|
+
await getService$2("components").syncConfigurations();
|
924
|
+
await getService$2("content-types").syncConfigurations();
|
925
|
+
await getService$2("permission").registerPermissions();
|
678
926
|
await history.bootstrap?.({ strapi });
|
927
|
+
await preview.bootstrap?.({ strapi });
|
679
928
|
};
|
680
929
|
const destroy = async ({ strapi: strapi2 }) => {
|
681
930
|
await history.destroy?.({ strapi: strapi2 });
|
@@ -1165,7 +1414,8 @@ const admin = {
|
|
1165
1414
|
};
|
1166
1415
|
const routes = {
|
1167
1416
|
admin,
|
1168
|
-
...history.routes ? history.routes : {}
|
1417
|
+
...history.routes ? history.routes : {},
|
1418
|
+
...preview.routes ? preview.routes : {}
|
1169
1419
|
};
|
1170
1420
|
const hasPermissionsSchema = yup$1.object({
|
1171
1421
|
actions: yup$1.array().of(yup$1.string()),
|
@@ -1176,6 +1426,11 @@ const { createPolicy } = policy;
|
|
1176
1426
|
const hasPermissions = createPolicy({
|
1177
1427
|
name: "plugin::content-manager.hasPermissions",
|
1178
1428
|
validator: validateHasPermissionsInput,
|
1429
|
+
/**
|
1430
|
+
* NOTE: Action aliases are currently not checked at this level (policy).
|
1431
|
+
* This is currently the intended behavior to avoid changing the behavior of API related permissions.
|
1432
|
+
* If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
|
1433
|
+
*/
|
1179
1434
|
handler(ctx, config = {}) {
|
1180
1435
|
const { actions = [], hasAtLeastOne = false } = config;
|
1181
1436
|
const { userAbility } = ctx.state;
|
@@ -1223,8 +1478,7 @@ const isSortable = (schema, name) => {
|
|
1223
1478
|
if (!_.has(schema.attributes, name)) {
|
1224
1479
|
return false;
|
1225
1480
|
}
|
1226
|
-
if (schema.modelType === "component" && name === "id")
|
1227
|
-
return false;
|
1481
|
+
if (schema.modelType === "component" && name === "id") return false;
|
1228
1482
|
const attribute = schema.attributes[name];
|
1229
1483
|
if (NON_SORTABLES.includes(attribute.type)) {
|
1230
1484
|
return false;
|
@@ -1369,8 +1623,7 @@ const createDefaultSettings = async (schema) => {
|
|
1369
1623
|
};
|
1370
1624
|
};
|
1371
1625
|
const syncSettings = async (configuration, schema) => {
|
1372
|
-
if (isEmpty(configuration.settings))
|
1373
|
-
return createDefaultSettings(schema);
|
1626
|
+
if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
|
1374
1627
|
const defaultField = getDefaultMainField(schema);
|
1375
1628
|
const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
|
1376
1629
|
return {
|
@@ -1417,7 +1670,7 @@ const createMetadasSchema = (schema) => {
|
|
1417
1670
|
if (!value) {
|
1418
1671
|
return yup$1.string();
|
1419
1672
|
}
|
1420
|
-
const targetSchema = getService$
|
1673
|
+
const targetSchema = getService$2("content-types").findContentType(
|
1421
1674
|
schema.attributes[key].targetModel
|
1422
1675
|
);
|
1423
1676
|
if (!targetSchema) {
|
@@ -1546,8 +1799,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1546
1799
|
}
|
1547
1800
|
switch (attribute.type) {
|
1548
1801
|
case "relation": {
|
1549
|
-
if (canCreate(attributePath))
|
1550
|
-
return body2;
|
1802
|
+
if (canCreate(attributePath)) return body2;
|
1551
1803
|
return set(attributePath, { set: [] }, body2);
|
1552
1804
|
}
|
1553
1805
|
case "component": {
|
@@ -1557,8 +1809,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1557
1809
|
]);
|
1558
1810
|
}
|
1559
1811
|
default: {
|
1560
|
-
if (canCreate(attributePath))
|
1561
|
-
return body2;
|
1812
|
+
if (canCreate(attributePath)) return body2;
|
1562
1813
|
return set(attributePath, null, body2);
|
1563
1814
|
}
|
1564
1815
|
}
|
@@ -1586,7 +1837,7 @@ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultiple
|
|
1586
1837
|
}
|
1587
1838
|
};
|
1588
1839
|
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1589
|
-
const documentMetadata2 = getService$
|
1840
|
+
const documentMetadata2 = getService$2("document-metadata");
|
1590
1841
|
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1591
1842
|
let {
|
1592
1843
|
meta: { availableLocales, availableStatus }
|
@@ -1612,8 +1863,8 @@ const createDocument = async (ctx, opts) => {
|
|
1612
1863
|
const { userAbility, user } = ctx.state;
|
1613
1864
|
const { model } = ctx.params;
|
1614
1865
|
const { body } = ctx.request;
|
1615
|
-
const documentManager2 = getService$
|
1616
|
-
const permissionChecker2 = getService$
|
1866
|
+
const documentManager2 = getService$2("document-manager");
|
1867
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1617
1868
|
if (permissionChecker2.cannot.create()) {
|
1618
1869
|
throw new errors.ForbiddenError();
|
1619
1870
|
}
|
@@ -1633,13 +1884,13 @@ const updateDocument = async (ctx, opts) => {
|
|
1633
1884
|
const { userAbility, user } = ctx.state;
|
1634
1885
|
const { id, model } = ctx.params;
|
1635
1886
|
const { body } = ctx.request;
|
1636
|
-
const documentManager2 = getService$
|
1637
|
-
const permissionChecker2 = getService$
|
1887
|
+
const documentManager2 = getService$2("document-manager");
|
1888
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1638
1889
|
if (permissionChecker2.cannot.update()) {
|
1639
1890
|
throw new errors.ForbiddenError();
|
1640
1891
|
}
|
1641
1892
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1642
|
-
const populate = await getService$
|
1893
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1643
1894
|
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1644
1895
|
const [documentVersion, documentExists] = await Promise.all([
|
1645
1896
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
@@ -1656,7 +1907,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1656
1907
|
throw new errors.ForbiddenError();
|
1657
1908
|
}
|
1658
1909
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1659
|
-
const setCreator = setCreatorFields({ user, isEdition: true });
|
1910
|
+
const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
|
1660
1911
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1661
1912
|
const sanitizedBody = await sanitizeFn(body);
|
1662
1913
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1670,14 +1921,14 @@ const collectionTypes = {
|
|
1670
1921
|
const { userAbility } = ctx.state;
|
1671
1922
|
const { model } = ctx.params;
|
1672
1923
|
const { query } = ctx.request;
|
1673
|
-
const documentMetadata2 = getService$
|
1674
|
-
const documentManager2 = getService$
|
1675
|
-
const permissionChecker2 = getService$
|
1924
|
+
const documentMetadata2 = getService$2("document-metadata");
|
1925
|
+
const documentManager2 = getService$2("document-manager");
|
1926
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1676
1927
|
if (permissionChecker2.cannot.read()) {
|
1677
1928
|
return ctx.forbidden();
|
1678
1929
|
}
|
1679
1930
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1680
|
-
const populate = await getService$
|
1931
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1681
1932
|
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1682
1933
|
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1683
1934
|
{ ...permissionQuery, populate, locale, status },
|
@@ -1706,13 +1957,13 @@ const collectionTypes = {
|
|
1706
1957
|
async findOne(ctx) {
|
1707
1958
|
const { userAbility } = ctx.state;
|
1708
1959
|
const { model, id } = ctx.params;
|
1709
|
-
const documentManager2 = getService$
|
1710
|
-
const permissionChecker2 = getService$
|
1960
|
+
const documentManager2 = getService$2("document-manager");
|
1961
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1711
1962
|
if (permissionChecker2.cannot.read()) {
|
1712
1963
|
return ctx.forbidden();
|
1713
1964
|
}
|
1714
1965
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1715
|
-
const populate = await getService$
|
1966
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1716
1967
|
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1717
1968
|
const version = await documentManager2.findOne(id, model, {
|
1718
1969
|
populate,
|
@@ -1728,7 +1979,7 @@ const collectionTypes = {
|
|
1728
1979
|
permissionChecker2,
|
1729
1980
|
model,
|
1730
1981
|
// @ts-expect-error TODO: fix
|
1731
|
-
{ id, locale, publishedAt: null },
|
1982
|
+
{ documentId: id, locale, publishedAt: null },
|
1732
1983
|
{ availableLocales: true, availableStatus: false }
|
1733
1984
|
);
|
1734
1985
|
ctx.body = { data: {}, meta };
|
@@ -1743,7 +1994,7 @@ const collectionTypes = {
|
|
1743
1994
|
async create(ctx) {
|
1744
1995
|
const { userAbility } = ctx.state;
|
1745
1996
|
const { model } = ctx.params;
|
1746
|
-
const permissionChecker2 = getService$
|
1997
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1747
1998
|
const [totalEntries, document] = await Promise.all([
|
1748
1999
|
strapi.db.query(model).count(),
|
1749
2000
|
createDocument(ctx)
|
@@ -1764,7 +2015,7 @@ const collectionTypes = {
|
|
1764
2015
|
async update(ctx) {
|
1765
2016
|
const { userAbility } = ctx.state;
|
1766
2017
|
const { model } = ctx.params;
|
1767
|
-
const permissionChecker2 = getService$
|
2018
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1768
2019
|
const updatedVersion = await updateDocument(ctx);
|
1769
2020
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1770
2021
|
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
@@ -1773,13 +2024,13 @@ const collectionTypes = {
|
|
1773
2024
|
const { userAbility, user } = ctx.state;
|
1774
2025
|
const { model, sourceId: id } = ctx.params;
|
1775
2026
|
const { body } = ctx.request;
|
1776
|
-
const documentManager2 = getService$
|
1777
|
-
const permissionChecker2 = getService$
|
2027
|
+
const documentManager2 = getService$2("document-manager");
|
2028
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1778
2029
|
if (permissionChecker2.cannot.create()) {
|
1779
2030
|
return ctx.forbidden();
|
1780
2031
|
}
|
1781
2032
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1782
|
-
const populate = await getService$
|
2033
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1783
2034
|
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1784
2035
|
const document = await documentManager2.findOne(id, model, {
|
1785
2036
|
populate,
|
@@ -1818,13 +2069,13 @@ const collectionTypes = {
|
|
1818
2069
|
async delete(ctx) {
|
1819
2070
|
const { userAbility } = ctx.state;
|
1820
2071
|
const { id, model } = ctx.params;
|
1821
|
-
const documentManager2 = getService$
|
1822
|
-
const permissionChecker2 = getService$
|
2072
|
+
const documentManager2 = getService$2("document-manager");
|
2073
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1823
2074
|
if (permissionChecker2.cannot.delete()) {
|
1824
2075
|
return ctx.forbidden();
|
1825
2076
|
}
|
1826
2077
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1827
|
-
const populate = await getService$
|
2078
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1828
2079
|
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1829
2080
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1830
2081
|
if (documentLocales.length === 0) {
|
@@ -1846,19 +2097,42 @@ const collectionTypes = {
|
|
1846
2097
|
const { userAbility } = ctx.state;
|
1847
2098
|
const { id, model } = ctx.params;
|
1848
2099
|
const { body } = ctx.request;
|
1849
|
-
const documentManager2 = getService$
|
1850
|
-
const permissionChecker2 = getService$
|
2100
|
+
const documentManager2 = getService$2("document-manager");
|
2101
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1851
2102
|
if (permissionChecker2.cannot.publish()) {
|
1852
2103
|
return ctx.forbidden();
|
1853
2104
|
}
|
1854
2105
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1855
2106
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1856
|
-
const populate = await getService$
|
1857
|
-
|
2107
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
2108
|
+
let document;
|
2109
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2110
|
+
const isCreate = isNil$1(id);
|
2111
|
+
if (isCreate) {
|
2112
|
+
if (permissionChecker2.cannot.create()) {
|
2113
|
+
throw new errors.ForbiddenError();
|
2114
|
+
}
|
2115
|
+
document = await createDocument(ctx, { populate });
|
2116
|
+
}
|
2117
|
+
const isUpdate = !isCreate;
|
2118
|
+
if (isUpdate) {
|
2119
|
+
const documentExists = documentManager2.exists(model, id);
|
2120
|
+
if (!documentExists) {
|
2121
|
+
throw new errors.NotFoundError("Document not found");
|
2122
|
+
}
|
2123
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
2124
|
+
if (!document) {
|
2125
|
+
if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
|
2126
|
+
throw new errors.ForbiddenError();
|
2127
|
+
}
|
2128
|
+
document = await updateDocument(ctx);
|
2129
|
+
} else if (permissionChecker2.can.update(document)) {
|
2130
|
+
await updateDocument(ctx);
|
2131
|
+
}
|
2132
|
+
}
|
1858
2133
|
if (permissionChecker2.cannot.publish(document)) {
|
1859
2134
|
throw new errors.ForbiddenError();
|
1860
2135
|
}
|
1861
|
-
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1862
2136
|
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1863
2137
|
locale
|
1864
2138
|
// TODO: Allow setting creator fields on publish
|
@@ -1878,13 +2152,13 @@ const collectionTypes = {
|
|
1878
2152
|
const { body } = ctx.request;
|
1879
2153
|
const { documentIds } = body;
|
1880
2154
|
await validateBulkActionInput(body);
|
1881
|
-
const documentManager2 = getService$
|
1882
|
-
const permissionChecker2 = getService$
|
2155
|
+
const documentManager2 = getService$2("document-manager");
|
2156
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1883
2157
|
if (permissionChecker2.cannot.publish()) {
|
1884
2158
|
return ctx.forbidden();
|
1885
2159
|
}
|
1886
2160
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1887
|
-
const populate = await getService$
|
2161
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1888
2162
|
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1889
2163
|
allowMultipleLocales: true
|
1890
2164
|
});
|
@@ -1909,12 +2183,14 @@ const collectionTypes = {
|
|
1909
2183
|
const { body } = ctx.request;
|
1910
2184
|
const { documentIds } = body;
|
1911
2185
|
await validateBulkActionInput(body);
|
1912
|
-
const documentManager2 = getService$
|
1913
|
-
const permissionChecker2 = getService$
|
2186
|
+
const documentManager2 = getService$2("document-manager");
|
2187
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1914
2188
|
if (permissionChecker2.cannot.unpublish()) {
|
1915
2189
|
return ctx.forbidden();
|
1916
2190
|
}
|
1917
|
-
const { locale } = await getDocumentLocaleAndStatus(body, model
|
2191
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2192
|
+
allowMultipleLocales: true
|
2193
|
+
});
|
1918
2194
|
const entityPromises = documentIds.map(
|
1919
2195
|
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1920
2196
|
);
|
@@ -1937,8 +2213,8 @@ const collectionTypes = {
|
|
1937
2213
|
const {
|
1938
2214
|
body: { discardDraft, ...body }
|
1939
2215
|
} = ctx.request;
|
1940
|
-
const documentManager2 = getService$
|
1941
|
-
const permissionChecker2 = getService$
|
2216
|
+
const documentManager2 = getService$2("document-manager");
|
2217
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1942
2218
|
if (permissionChecker2.cannot.unpublish()) {
|
1943
2219
|
return ctx.forbidden();
|
1944
2220
|
}
|
@@ -1946,7 +2222,7 @@ const collectionTypes = {
|
|
1946
2222
|
return ctx.forbidden();
|
1947
2223
|
}
|
1948
2224
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1949
|
-
const populate = await getService$
|
2225
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1950
2226
|
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1951
2227
|
const document = await documentManager2.findOne(id, model, {
|
1952
2228
|
populate,
|
@@ -1977,13 +2253,13 @@ const collectionTypes = {
|
|
1977
2253
|
const { userAbility } = ctx.state;
|
1978
2254
|
const { id, model } = ctx.params;
|
1979
2255
|
const { body } = ctx.request;
|
1980
|
-
const documentManager2 = getService$
|
1981
|
-
const permissionChecker2 = getService$
|
2256
|
+
const documentManager2 = getService$2("document-manager");
|
2257
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1982
2258
|
if (permissionChecker2.cannot.discard()) {
|
1983
2259
|
return ctx.forbidden();
|
1984
2260
|
}
|
1985
2261
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1986
|
-
const populate = await getService$
|
2262
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1987
2263
|
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1988
2264
|
const document = await documentManager2.findOne(id, model, {
|
1989
2265
|
populate,
|
@@ -2008,13 +2284,13 @@ const collectionTypes = {
|
|
2008
2284
|
const { query, body } = ctx.request;
|
2009
2285
|
const { documentIds } = body;
|
2010
2286
|
await validateBulkActionInput(body);
|
2011
|
-
const documentManager2 = getService$
|
2012
|
-
const permissionChecker2 = getService$
|
2287
|
+
const documentManager2 = getService$2("document-manager");
|
2288
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2013
2289
|
if (permissionChecker2.cannot.delete()) {
|
2014
2290
|
return ctx.forbidden();
|
2015
2291
|
}
|
2016
2292
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2017
|
-
const populate = await getService$
|
2293
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2018
2294
|
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2019
2295
|
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2020
2296
|
populate,
|
@@ -2035,13 +2311,13 @@ const collectionTypes = {
|
|
2035
2311
|
async countDraftRelations(ctx) {
|
2036
2312
|
const { userAbility } = ctx.state;
|
2037
2313
|
const { model, id } = ctx.params;
|
2038
|
-
const documentManager2 = getService$
|
2039
|
-
const permissionChecker2 = getService$
|
2314
|
+
const documentManager2 = getService$2("document-manager");
|
2315
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2040
2316
|
if (permissionChecker2.cannot.read()) {
|
2041
2317
|
return ctx.forbidden();
|
2042
2318
|
}
|
2043
2319
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2044
|
-
const populate = await getService$
|
2320
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2045
2321
|
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
2046
2322
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
2047
2323
|
if (!entity) {
|
@@ -2060,8 +2336,8 @@ const collectionTypes = {
|
|
2060
2336
|
const ids = ctx.request.query.documentIds;
|
2061
2337
|
const locale = ctx.request.query.locale;
|
2062
2338
|
const { model } = ctx.params;
|
2063
|
-
const documentManager2 = getService$
|
2064
|
-
const permissionChecker2 = getService$
|
2339
|
+
const documentManager2 = getService$2("document-manager");
|
2340
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2065
2341
|
if (permissionChecker2.cannot.read()) {
|
2066
2342
|
return ctx.forbidden();
|
2067
2343
|
}
|
@@ -2085,13 +2361,13 @@ const collectionTypes = {
|
|
2085
2361
|
};
|
2086
2362
|
const components$1 = {
|
2087
2363
|
findComponents(ctx) {
|
2088
|
-
const components2 = getService$
|
2089
|
-
const { toDto } = getService$
|
2364
|
+
const components2 = getService$2("components").findAllComponents();
|
2365
|
+
const { toDto } = getService$2("data-mapper");
|
2090
2366
|
ctx.body = { data: components2.map(toDto) };
|
2091
2367
|
},
|
2092
2368
|
async findComponentConfiguration(ctx) {
|
2093
2369
|
const { uid: uid2 } = ctx.params;
|
2094
|
-
const componentService = getService$
|
2370
|
+
const componentService = getService$2("components");
|
2095
2371
|
const component = componentService.findComponent(uid2);
|
2096
2372
|
if (!component) {
|
2097
2373
|
return ctx.notFound("component.notFound");
|
@@ -2108,7 +2384,7 @@ const components$1 = {
|
|
2108
2384
|
async updateComponentConfiguration(ctx) {
|
2109
2385
|
const { uid: uid2 } = ctx.params;
|
2110
2386
|
const { body } = ctx.request;
|
2111
|
-
const componentService = getService$
|
2387
|
+
const componentService = getService$2("components");
|
2112
2388
|
const component = componentService.findComponent(uid2);
|
2113
2389
|
if (!component) {
|
2114
2390
|
return ctx.notFound("component.notFound");
|
@@ -2142,12 +2418,12 @@ const contentTypes = {
|
|
2142
2418
|
} catch (error) {
|
2143
2419
|
return ctx.send({ error }, 400);
|
2144
2420
|
}
|
2145
|
-
const contentTypes2 = getService$
|
2146
|
-
const { toDto } = getService$
|
2421
|
+
const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
|
2422
|
+
const { toDto } = getService$2("data-mapper");
|
2147
2423
|
ctx.body = { data: contentTypes2.map(toDto) };
|
2148
2424
|
},
|
2149
2425
|
async findContentTypesSettings(ctx) {
|
2150
|
-
const { findAllContentTypes, findConfiguration } = getService$
|
2426
|
+
const { findAllContentTypes, findConfiguration } = getService$2("content-types");
|
2151
2427
|
const contentTypes2 = await findAllContentTypes();
|
2152
2428
|
const configurations = await Promise.all(
|
2153
2429
|
contentTypes2.map(async (contentType) => {
|
@@ -2161,7 +2437,7 @@ const contentTypes = {
|
|
2161
2437
|
},
|
2162
2438
|
async findContentTypeConfiguration(ctx) {
|
2163
2439
|
const { uid: uid2 } = ctx.params;
|
2164
|
-
const contentTypeService = getService$
|
2440
|
+
const contentTypeService = getService$2("content-types");
|
2165
2441
|
const contentType = await contentTypeService.findContentType(uid2);
|
2166
2442
|
if (!contentType) {
|
2167
2443
|
return ctx.notFound("contentType.notFound");
|
@@ -2183,13 +2459,13 @@ const contentTypes = {
|
|
2183
2459
|
const { userAbility } = ctx.state;
|
2184
2460
|
const { uid: uid2 } = ctx.params;
|
2185
2461
|
const { body } = ctx.request;
|
2186
|
-
const contentTypeService = getService$
|
2187
|
-
const metricsService = getService$
|
2462
|
+
const contentTypeService = getService$2("content-types");
|
2463
|
+
const metricsService = getService$2("metrics");
|
2188
2464
|
const contentType = await contentTypeService.findContentType(uid2);
|
2189
2465
|
if (!contentType) {
|
2190
2466
|
return ctx.notFound("contentType.notFound");
|
2191
2467
|
}
|
2192
|
-
if (!getService$
|
2468
|
+
if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
|
2193
2469
|
return ctx.forbidden();
|
2194
2470
|
}
|
2195
2471
|
let input;
|
@@ -2222,10 +2498,10 @@ const contentTypes = {
|
|
2222
2498
|
};
|
2223
2499
|
const init = {
|
2224
2500
|
getInitData(ctx) {
|
2225
|
-
const { toDto } = getService$
|
2226
|
-
const { findAllComponents } = getService$
|
2227
|
-
const { getAllFieldSizes } = getService$
|
2228
|
-
const { findAllContentTypes } = getService$
|
2501
|
+
const { toDto } = getService$2("data-mapper");
|
2502
|
+
const { findAllComponents } = getService$2("components");
|
2503
|
+
const { getAllFieldSizes } = getService$2("field-sizes");
|
2504
|
+
const { findAllContentTypes } = getService$2("content-types");
|
2229
2505
|
ctx.body = {
|
2230
2506
|
data: {
|
2231
2507
|
fieldSizes: getAllFieldSizes(),
|
@@ -2261,36 +2537,41 @@ const addFiltersClause = (params, filtersClause) => {
|
|
2261
2537
|
params.filters.$and.push(filtersClause);
|
2262
2538
|
};
|
2263
2539
|
const sanitizeMainField = (model, mainField, userAbility) => {
|
2264
|
-
const permissionChecker2 = getService$
|
2540
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2265
2541
|
userAbility,
|
2266
2542
|
model: model.uid
|
2267
2543
|
});
|
2268
|
-
|
2544
|
+
const isMainFieldListable = isListable(model, mainField);
|
2545
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2546
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2269
2547
|
return "id";
|
2270
2548
|
}
|
2271
|
-
if (
|
2272
|
-
|
2273
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2274
|
-
userAbility,
|
2275
|
-
model: "plugin::users-permissions.user"
|
2276
|
-
});
|
2277
|
-
if (userPermissionChecker.can.read()) {
|
2278
|
-
return "name";
|
2279
|
-
}
|
2280
|
-
}
|
2281
|
-
return "id";
|
2549
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2550
|
+
return "name";
|
2282
2551
|
}
|
2283
2552
|
return mainField;
|
2284
2553
|
};
|
2285
|
-
const addStatusToRelations = async (
|
2286
|
-
if (!contentTypes$1.hasDraftAndPublish(strapi.
|
2554
|
+
const addStatusToRelations = async (targetUid, relations2) => {
|
2555
|
+
if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
2287
2556
|
return relations2;
|
2288
2557
|
}
|
2289
|
-
const documentMetadata2 = getService$
|
2290
|
-
|
2558
|
+
const documentMetadata2 = getService$2("document-metadata");
|
2559
|
+
if (!relations2.length) {
|
2560
|
+
return relations2;
|
2561
|
+
}
|
2562
|
+
const firstRelation = relations2[0];
|
2563
|
+
const filters = {
|
2564
|
+
documentId: { $in: relations2.map((r) => r.documentId) },
|
2565
|
+
// NOTE: find the "opposite" status
|
2566
|
+
publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
|
2567
|
+
};
|
2568
|
+
const availableStatus = await strapi.query(targetUid).findMany({
|
2569
|
+
select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
|
2570
|
+
filters
|
2571
|
+
});
|
2291
2572
|
return relations2.map((relation) => {
|
2292
|
-
const availableStatuses =
|
2293
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2573
|
+
const availableStatuses = availableStatus.filter(
|
2574
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2294
2575
|
);
|
2295
2576
|
return {
|
2296
2577
|
...relation,
|
@@ -2311,11 +2592,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2311
2592
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2312
2593
|
const isSourceLocalized = isLocalized(sourceModel);
|
2313
2594
|
const isTargetLocalized = isLocalized(targetModel);
|
2314
|
-
let validatedLocale = locale;
|
2315
|
-
if (!targetModel || !isTargetLocalized)
|
2316
|
-
validatedLocale = void 0;
|
2317
2595
|
return {
|
2318
|
-
locale
|
2596
|
+
locale,
|
2319
2597
|
isSourceLocalized,
|
2320
2598
|
isTargetLocalized
|
2321
2599
|
};
|
@@ -2324,8 +2602,7 @@ const validateStatus = (sourceUid, status) => {
|
|
2324
2602
|
const sourceModel = strapi.getModel(sourceUid);
|
2325
2603
|
const isDP = contentTypes$1.hasDraftAndPublish;
|
2326
2604
|
const isSourceDP = isDP(sourceModel);
|
2327
|
-
if (!isSourceDP)
|
2328
|
-
return { status: void 0 };
|
2605
|
+
if (!isSourceDP) return { status: void 0 };
|
2329
2606
|
switch (status) {
|
2330
2607
|
case "published":
|
2331
2608
|
return { status: "published" };
|
@@ -2355,7 +2632,7 @@ const relations = {
|
|
2355
2632
|
ctx.request?.query?.locale
|
2356
2633
|
);
|
2357
2634
|
const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
|
2358
|
-
const permissionChecker2 = getService$
|
2635
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2359
2636
|
userAbility,
|
2360
2637
|
model
|
2361
2638
|
});
|
@@ -2380,7 +2657,7 @@ const relations = {
|
|
2380
2657
|
where.id = id;
|
2381
2658
|
}
|
2382
2659
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2383
|
-
const populate = await getService$
|
2660
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2384
2661
|
const currentEntity = await strapi.db.query(model).findOne({
|
2385
2662
|
where,
|
2386
2663
|
populate
|
@@ -2395,7 +2672,7 @@ const relations = {
|
|
2395
2672
|
}
|
2396
2673
|
entryId = currentEntity.id;
|
2397
2674
|
}
|
2398
|
-
const modelConfig = isComponent2 ? await getService$
|
2675
|
+
const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
|
2399
2676
|
const targetSchema = strapi.getModel(targetUid);
|
2400
2677
|
const mainField = flow(
|
2401
2678
|
prop(`metadatas.${targetField}.edit.mainField`),
|
@@ -2418,7 +2695,7 @@ const relations = {
|
|
2418
2695
|
attribute,
|
2419
2696
|
fieldsToSelect,
|
2420
2697
|
mainField,
|
2421
|
-
source: { schema: sourceSchema },
|
2698
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2422
2699
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2423
2700
|
sourceSchema,
|
2424
2701
|
targetSchema,
|
@@ -2440,7 +2717,8 @@ const relations = {
|
|
2440
2717
|
fieldsToSelect,
|
2441
2718
|
mainField,
|
2442
2719
|
source: {
|
2443
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2720
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2721
|
+
isLocalized: isSourceLocalized
|
2444
2722
|
},
|
2445
2723
|
target: {
|
2446
2724
|
schema: { uid: targetUid },
|
@@ -2448,7 +2726,7 @@ const relations = {
|
|
2448
2726
|
}
|
2449
2727
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2450
2728
|
const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
2451
|
-
const permissionChecker2 = getService$
|
2729
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2452
2730
|
userAbility: ctx.state.userAbility,
|
2453
2731
|
model: targetUid
|
2454
2732
|
});
|
@@ -2478,12 +2756,16 @@ const relations = {
|
|
2478
2756
|
} else {
|
2479
2757
|
where.id = id;
|
2480
2758
|
}
|
2481
|
-
|
2482
|
-
|
2759
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2760
|
+
if (!isEmpty(publishedAt)) {
|
2761
|
+
where[`${alias}.published_at`] = publishedAt;
|
2483
2762
|
}
|
2484
|
-
if (
|
2763
|
+
if (isTargetLocalized && locale) {
|
2485
2764
|
where[`${alias}.locale`] = locale;
|
2486
2765
|
}
|
2766
|
+
if (isSourceLocalized && locale) {
|
2767
|
+
where.locale = locale;
|
2768
|
+
}
|
2487
2769
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2488
2770
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2489
2771
|
}
|
@@ -2501,7 +2783,8 @@ const relations = {
|
|
2501
2783
|
id: { $notIn: uniq(idsToOmit) }
|
2502
2784
|
});
|
2503
2785
|
}
|
2504
|
-
const
|
2786
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2787
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2505
2788
|
ctx.body = {
|
2506
2789
|
...res,
|
2507
2790
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2516,29 +2799,39 @@ const relations = {
|
|
2516
2799
|
attribute,
|
2517
2800
|
targetField,
|
2518
2801
|
fieldsToSelect,
|
2519
|
-
|
2520
|
-
|
2521
|
-
}
|
2522
|
-
target: {
|
2523
|
-
schema: { uid: targetUid }
|
2524
|
-
}
|
2802
|
+
status,
|
2803
|
+
source: { schema: sourceSchema },
|
2804
|
+
target: { schema: targetSchema }
|
2525
2805
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2526
|
-
const
|
2806
|
+
const { uid: sourceUid } = sourceSchema;
|
2807
|
+
const { uid: targetUid } = targetSchema;
|
2808
|
+
const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
|
2527
2809
|
const dbQuery = strapi.db.query(sourceUid);
|
2528
2810
|
const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
|
2811
|
+
const filters = {};
|
2812
|
+
if (sourceSchema?.options?.draftAndPublish) {
|
2813
|
+
if (targetSchema?.options?.draftAndPublish) {
|
2814
|
+
if (status === "published") {
|
2815
|
+
filters.publishedAt = { $notNull: true };
|
2816
|
+
} else {
|
2817
|
+
filters.publishedAt = { $null: true };
|
2818
|
+
}
|
2819
|
+
}
|
2820
|
+
} else if (targetSchema?.options?.draftAndPublish) {
|
2821
|
+
filters.publishedAt = { $null: true };
|
2822
|
+
}
|
2529
2823
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2530
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2824
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2531
2825
|
ordering: "desc",
|
2532
2826
|
page: ctx.request.query.page,
|
2533
|
-
pageSize: ctx.request.query.pageSize
|
2827
|
+
pageSize: ctx.request.query.pageSize,
|
2828
|
+
filters
|
2534
2829
|
});
|
2535
2830
|
const loadedIds = res.results.map((item) => item.id);
|
2536
2831
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2537
2832
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2538
2833
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2539
|
-
ordering: "desc"
|
2540
|
-
page: ctx.request.query.page,
|
2541
|
-
pageSize: ctx.request.query.pageSize
|
2834
|
+
ordering: "desc"
|
2542
2835
|
});
|
2543
2836
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2544
2837
|
ctx.body = {
|
@@ -2553,10 +2846,10 @@ const relations = {
|
|
2553
2846
|
}
|
2554
2847
|
};
|
2555
2848
|
const buildPopulateFromQuery = async (query, model) => {
|
2556
|
-
return getService$
|
2849
|
+
return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
|
2557
2850
|
};
|
2558
2851
|
const findDocument = async (query, uid2, opts = {}) => {
|
2559
|
-
const documentManager2 = getService$
|
2852
|
+
const documentManager2 = getService$2("document-manager");
|
2560
2853
|
const populate = await buildPopulateFromQuery(query, uid2);
|
2561
2854
|
return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
|
2562
2855
|
};
|
@@ -2564,8 +2857,8 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2564
2857
|
const { user, userAbility } = ctx.state;
|
2565
2858
|
const { model } = ctx.params;
|
2566
2859
|
const { body, query } = ctx.request;
|
2567
|
-
const documentManager2 = getService$
|
2568
|
-
const permissionChecker2 = getService$
|
2860
|
+
const documentManager2 = getService$2("document-manager");
|
2861
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2569
2862
|
if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
|
2570
2863
|
throw new errors.ForbiddenError();
|
2571
2864
|
}
|
@@ -2606,7 +2899,7 @@ const singleTypes = {
|
|
2606
2899
|
const { userAbility } = ctx.state;
|
2607
2900
|
const { model } = ctx.params;
|
2608
2901
|
const { query = {} } = ctx.request;
|
2609
|
-
const permissionChecker2 = getService$
|
2902
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2610
2903
|
if (permissionChecker2.cannot.read()) {
|
2611
2904
|
return ctx.forbidden();
|
2612
2905
|
}
|
@@ -2625,7 +2918,7 @@ const singleTypes = {
|
|
2625
2918
|
permissionChecker2,
|
2626
2919
|
model,
|
2627
2920
|
// @ts-expect-error - fix types
|
2628
|
-
{
|
2921
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2629
2922
|
{ availableLocales: true, availableStatus: false }
|
2630
2923
|
);
|
2631
2924
|
ctx.body = { data: {}, meta };
|
@@ -2640,7 +2933,7 @@ const singleTypes = {
|
|
2640
2933
|
async createOrUpdate(ctx) {
|
2641
2934
|
const { userAbility } = ctx.state;
|
2642
2935
|
const { model } = ctx.params;
|
2643
|
-
const permissionChecker2 = getService$
|
2936
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2644
2937
|
const document = await createOrUpdateDocument(ctx);
|
2645
2938
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2646
2939
|
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
@@ -2649,8 +2942,8 @@ const singleTypes = {
|
|
2649
2942
|
const { userAbility } = ctx.state;
|
2650
2943
|
const { model } = ctx.params;
|
2651
2944
|
const { query = {} } = ctx.request;
|
2652
|
-
const documentManager2 = getService$
|
2653
|
-
const permissionChecker2 = getService$
|
2945
|
+
const documentManager2 = getService$2("document-manager");
|
2946
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2654
2947
|
if (permissionChecker2.cannot.delete()) {
|
2655
2948
|
return ctx.forbidden();
|
2656
2949
|
}
|
@@ -2678,8 +2971,8 @@ const singleTypes = {
|
|
2678
2971
|
const { userAbility } = ctx.state;
|
2679
2972
|
const { model } = ctx.params;
|
2680
2973
|
const { query = {} } = ctx.request;
|
2681
|
-
const documentManager2 = getService$
|
2682
|
-
const permissionChecker2 = getService$
|
2974
|
+
const documentManager2 = getService$2("document-manager");
|
2975
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2683
2976
|
if (permissionChecker2.cannot.publish()) {
|
2684
2977
|
return ctx.forbidden();
|
2685
2978
|
}
|
@@ -2707,8 +3000,8 @@ const singleTypes = {
|
|
2707
3000
|
body: { discardDraft, ...body },
|
2708
3001
|
query = {}
|
2709
3002
|
} = ctx.request;
|
2710
|
-
const documentManager2 = getService$
|
2711
|
-
const permissionChecker2 = getService$
|
3003
|
+
const documentManager2 = getService$2("document-manager");
|
3004
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2712
3005
|
if (permissionChecker2.cannot.unpublish()) {
|
2713
3006
|
return ctx.forbidden();
|
2714
3007
|
}
|
@@ -2742,8 +3035,8 @@ const singleTypes = {
|
|
2742
3035
|
const { userAbility } = ctx.state;
|
2743
3036
|
const { model } = ctx.params;
|
2744
3037
|
const { body, query = {} } = ctx.request;
|
2745
|
-
const documentManager2 = getService$
|
2746
|
-
const permissionChecker2 = getService$
|
3038
|
+
const documentManager2 = getService$2("document-manager");
|
3039
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2747
3040
|
if (permissionChecker2.cannot.discard()) {
|
2748
3041
|
return ctx.forbidden();
|
2749
3042
|
}
|
@@ -2766,8 +3059,8 @@ const singleTypes = {
|
|
2766
3059
|
const { userAbility } = ctx.state;
|
2767
3060
|
const { model } = ctx.params;
|
2768
3061
|
const { query } = ctx.request;
|
2769
|
-
const documentManager2 = getService$
|
2770
|
-
const permissionChecker2 = getService$
|
3062
|
+
const documentManager2 = getService$2("document-manager");
|
3063
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2771
3064
|
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2772
3065
|
if (permissionChecker2.cannot.read()) {
|
2773
3066
|
return ctx.forbidden();
|
@@ -2791,7 +3084,7 @@ const uid$1 = {
|
|
2791
3084
|
const { query = {} } = ctx.request;
|
2792
3085
|
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2793
3086
|
await validateUIDField(contentTypeUID, field);
|
2794
|
-
const uidService = getService$
|
3087
|
+
const uidService = getService$2("uid");
|
2795
3088
|
ctx.body = {
|
2796
3089
|
data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
|
2797
3090
|
};
|
@@ -2803,7 +3096,7 @@ const uid$1 = {
|
|
2803
3096
|
const { query = {} } = ctx.request;
|
2804
3097
|
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2805
3098
|
await validateUIDField(contentTypeUID, field);
|
2806
|
-
const uidService = getService$
|
3099
|
+
const uidService = getService$2("uid");
|
2807
3100
|
const isAvailable = await uidService.checkUIDAvailability({
|
2808
3101
|
contentTypeUID,
|
2809
3102
|
field,
|
@@ -2824,7 +3117,8 @@ const controllers = {
|
|
2824
3117
|
relations,
|
2825
3118
|
"single-types": singleTypes,
|
2826
3119
|
uid: uid$1,
|
2827
|
-
...history.controllers ? history.controllers : {}
|
3120
|
+
...history.controllers ? history.controllers : {},
|
3121
|
+
...preview.controllers ? preview.controllers : {}
|
2828
3122
|
};
|
2829
3123
|
const keys = {
|
2830
3124
|
CONFIGURATION: "configuration"
|
@@ -2953,18 +3247,15 @@ async function syncMetadatas(configuration, schema) {
|
|
2953
3247
|
_.set(updatedMeta, ["list", "searchable"], false);
|
2954
3248
|
_.set(acc, [key], updatedMeta);
|
2955
3249
|
}
|
2956
|
-
if (!_.has(edit, "mainField"))
|
2957
|
-
return acc;
|
3250
|
+
if (!_.has(edit, "mainField")) return acc;
|
2958
3251
|
if (!isRelation$1(attr)) {
|
2959
3252
|
_.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
|
2960
3253
|
_.set(acc, [key], updatedMeta);
|
2961
3254
|
return acc;
|
2962
3255
|
}
|
2963
|
-
if (edit.mainField === "id")
|
2964
|
-
return acc;
|
3256
|
+
if (edit.mainField === "id") return acc;
|
2965
3257
|
const targetSchema = getTargetSchema(attr.targetModel);
|
2966
|
-
if (!targetSchema)
|
2967
|
-
return acc;
|
3258
|
+
if (!targetSchema) return acc;
|
2968
3259
|
if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
|
2969
3260
|
_.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
|
2970
3261
|
_.set(acc, [key], updatedMeta);
|
@@ -2975,12 +3266,12 @@ async function syncMetadatas(configuration, schema) {
|
|
2975
3266
|
return _.assign(metasWithDefaults, updatedMetas);
|
2976
3267
|
}
|
2977
3268
|
const getTargetSchema = (targetModel) => {
|
2978
|
-
return getService$
|
3269
|
+
return getService$2("content-types").findContentType(targetModel);
|
2979
3270
|
};
|
2980
3271
|
const DEFAULT_LIST_LENGTH = 4;
|
2981
3272
|
const MAX_ROW_SIZE = 12;
|
2982
3273
|
const isAllowedFieldSize = (type, size) => {
|
2983
|
-
const { getFieldSize } = getService$
|
3274
|
+
const { getFieldSize } = getService$2("field-sizes");
|
2984
3275
|
const fieldSize = getFieldSize(type);
|
2985
3276
|
if (!fieldSize.isResizable && size !== fieldSize.default) {
|
2986
3277
|
return false;
|
@@ -2988,7 +3279,7 @@ const isAllowedFieldSize = (type, size) => {
|
|
2988
3279
|
return size <= MAX_ROW_SIZE;
|
2989
3280
|
};
|
2990
3281
|
const getDefaultFieldSize = (attribute) => {
|
2991
|
-
const { hasFieldSize, getFieldSize } = getService$
|
3282
|
+
const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
|
2992
3283
|
return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
|
2993
3284
|
};
|
2994
3285
|
async function createDefaultLayouts(schema) {
|
@@ -3009,8 +3300,7 @@ function createDefaultEditLayout(schema) {
|
|
3009
3300
|
return appendToEditLayout([], keys2, schema);
|
3010
3301
|
}
|
3011
3302
|
function syncLayouts(configuration, schema) {
|
3012
|
-
if (_.isEmpty(configuration.layouts))
|
3013
|
-
return createDefaultLayouts(schema);
|
3303
|
+
if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
|
3014
3304
|
const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
|
3015
3305
|
let cleanList = list.filter((attr) => isListable(schema, attr));
|
3016
3306
|
const cleanEditRelations = editRelations.filter(
|
@@ -3021,9 +3311,8 @@ function syncLayouts(configuration, schema) {
|
|
3021
3311
|
for (const row of edit) {
|
3022
3312
|
const newRow = [];
|
3023
3313
|
for (const el of row) {
|
3024
|
-
if (!hasEditableAttribute(schema, el.name))
|
3025
|
-
|
3026
|
-
const { hasFieldSize } = getService$1("field-sizes");
|
3314
|
+
if (!hasEditableAttribute(schema, el.name)) continue;
|
3315
|
+
const { hasFieldSize } = getService$2("field-sizes");
|
3027
3316
|
const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
|
3028
3317
|
if (!isAllowedFieldSize(fieldType, el.size)) {
|
3029
3318
|
elementsToReAppend.push(el.name);
|
@@ -3053,8 +3342,7 @@ function syncLayouts(configuration, schema) {
|
|
3053
3342
|
};
|
3054
3343
|
}
|
3055
3344
|
const appendToEditLayout = (layout = [], keysToAppend, schema) => {
|
3056
|
-
if (keysToAppend.length === 0)
|
3057
|
-
return layout;
|
3345
|
+
if (keysToAppend.length === 0) return layout;
|
3058
3346
|
let currentRowIndex = Math.max(layout.length - 1, 0);
|
3059
3347
|
if (!layout[currentRowIndex]) {
|
3060
3348
|
layout[currentRowIndex] = [];
|
@@ -3163,17 +3451,17 @@ const configurationService$1 = createConfigurationService({
|
|
3163
3451
|
isComponent: true,
|
3164
3452
|
prefix: STORE_KEY_PREFIX,
|
3165
3453
|
getModels() {
|
3166
|
-
const { toContentManagerModel } = getService$
|
3454
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3167
3455
|
return mapValues(toContentManagerModel, strapi.components);
|
3168
3456
|
}
|
3169
3457
|
});
|
3170
3458
|
const components = ({ strapi: strapi2 }) => ({
|
3171
3459
|
findAllComponents() {
|
3172
|
-
const { toContentManagerModel } = getService$
|
3460
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3173
3461
|
return Object.values(strapi2.components).map(toContentManagerModel);
|
3174
3462
|
},
|
3175
3463
|
findComponent(uid2) {
|
3176
|
-
const { toContentManagerModel } = getService$
|
3464
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3177
3465
|
const component = strapi2.components[uid2];
|
3178
3466
|
return isNil$1(component) ? component : toContentManagerModel(component);
|
3179
3467
|
},
|
@@ -3224,17 +3512,17 @@ const configurationService = createConfigurationService({
|
|
3224
3512
|
storeUtils,
|
3225
3513
|
prefix: "content_types",
|
3226
3514
|
getModels() {
|
3227
|
-
const { toContentManagerModel } = getService$
|
3515
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3228
3516
|
return mapValues(toContentManagerModel, strapi.contentTypes);
|
3229
3517
|
}
|
3230
3518
|
});
|
3231
3519
|
const service = ({ strapi: strapi2 }) => ({
|
3232
3520
|
findAllContentTypes() {
|
3233
|
-
const { toContentManagerModel } = getService$
|
3521
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3234
3522
|
return Object.values(strapi2.contentTypes).map(toContentManagerModel);
|
3235
3523
|
},
|
3236
3524
|
findContentType(uid2) {
|
3237
|
-
const { toContentManagerModel } = getService$
|
3525
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3238
3526
|
const contentType = strapi2.contentTypes[uid2];
|
3239
3527
|
return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
|
3240
3528
|
},
|
@@ -3263,7 +3551,7 @@ const service = ({ strapi: strapi2 }) => ({
|
|
3263
3551
|
return this.findConfiguration(contentType);
|
3264
3552
|
},
|
3265
3553
|
findComponentsConfigurations(contentType) {
|
3266
|
-
return getService$
|
3554
|
+
return getService$2("components").findComponentsConfigurations(contentType);
|
3267
3555
|
},
|
3268
3556
|
syncConfigurations() {
|
3269
3557
|
return configurationService.syncConfigurations();
|
@@ -3444,12 +3732,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3444
3732
|
ability: userAbility,
|
3445
3733
|
model
|
3446
3734
|
});
|
3447
|
-
const
|
3735
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3736
|
+
const toSubject = (entity) => {
|
3737
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3738
|
+
};
|
3448
3739
|
const can = (action, entity, field) => {
|
3449
|
-
|
3740
|
+
const subject = toSubject(entity);
|
3741
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3742
|
+
return (
|
3743
|
+
// Test the original action to see if it passes
|
3744
|
+
userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
|
3745
|
+
aliases.some((alias) => userAbility.can(alias, subject, field))
|
3746
|
+
);
|
3450
3747
|
};
|
3451
3748
|
const cannot = (action, entity, field) => {
|
3452
|
-
|
3749
|
+
const subject = toSubject(entity);
|
3750
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3751
|
+
return (
|
3752
|
+
// Test both the original action
|
3753
|
+
userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
|
3754
|
+
aliases.every((alias) => userAbility.cannot(alias, subject, field))
|
3755
|
+
);
|
3453
3756
|
};
|
3454
3757
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3455
3758
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3520,7 +3823,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3520
3823
|
return userAbility.can(action);
|
3521
3824
|
},
|
3522
3825
|
async registerPermissions() {
|
3523
|
-
const displayedContentTypes = getService$
|
3826
|
+
const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
|
3524
3827
|
const contentTypesUids = displayedContentTypes.map(prop("uid"));
|
3525
3828
|
const actions = [
|
3526
3829
|
{
|
@@ -3605,6 +3908,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
|
|
3605
3908
|
if (initialPopulate) {
|
3606
3909
|
return initialPopulate;
|
3607
3910
|
}
|
3911
|
+
if (attributeName === "localizations") {
|
3912
|
+
const validationPopulate = getPopulateForValidation(model.uid);
|
3913
|
+
return {
|
3914
|
+
populate: validationPopulate.populate
|
3915
|
+
};
|
3916
|
+
}
|
3608
3917
|
if (!isVisibleAttribute$1(model, attributeName)) {
|
3609
3918
|
return true;
|
3610
3919
|
}
|
@@ -3664,6 +3973,9 @@ const getDeepPopulate = (uid2, {
|
|
3664
3973
|
return {};
|
3665
3974
|
}
|
3666
3975
|
const model = strapi.getModel(uid2);
|
3976
|
+
if (!model) {
|
3977
|
+
return {};
|
3978
|
+
}
|
3667
3979
|
return Object.keys(model.attributes).reduce(
|
3668
3980
|
(populateAcc, attributeName) => merge(
|
3669
3981
|
populateAcc,
|
@@ -3683,40 +3995,46 @@ const getDeepPopulate = (uid2, {
|
|
3683
3995
|
{}
|
3684
3996
|
);
|
3685
3997
|
};
|
3686
|
-
const
|
3687
|
-
|
3688
|
-
|
3689
|
-
countOne = false,
|
3690
|
-
maxLevel = Infinity
|
3691
|
-
} = {}, level = 1) => {
|
3692
|
-
if (level > maxLevel) {
|
3998
|
+
const getPopulateForValidation = (uid2) => {
|
3999
|
+
const model = strapi.getModel(uid2);
|
4000
|
+
if (!model) {
|
3693
4001
|
return {};
|
3694
4002
|
}
|
3695
|
-
const model = strapi.getModel(uid2);
|
3696
4003
|
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3697
|
-
if (
|
4004
|
+
if (isScalarAttribute(attribute)) {
|
4005
|
+
if (getDoesAttributeRequireValidation(attribute)) {
|
4006
|
+
populateAcc.fields = populateAcc.fields || [];
|
4007
|
+
populateAcc.fields.push(attributeName);
|
4008
|
+
}
|
3698
4009
|
return populateAcc;
|
3699
4010
|
}
|
3700
|
-
if (
|
3701
|
-
|
3702
|
-
|
3703
|
-
|
4011
|
+
if (isComponent(attribute)) {
|
4012
|
+
const component = attribute.component;
|
4013
|
+
const componentResult = getPopulateForValidation(component);
|
4014
|
+
if (Object.keys(componentResult).length > 0) {
|
4015
|
+
populateAcc.populate = populateAcc.populate || {};
|
4016
|
+
populateAcc.populate[attributeName] = componentResult;
|
4017
|
+
}
|
4018
|
+
return populateAcc;
|
3704
4019
|
}
|
3705
|
-
|
3706
|
-
|
3707
|
-
|
3708
|
-
|
3709
|
-
|
3710
|
-
|
3711
|
-
|
3712
|
-
|
3713
|
-
|
3714
|
-
countOne,
|
3715
|
-
maxLevel
|
4020
|
+
if (isDynamicZone(attribute)) {
|
4021
|
+
const components2 = attribute.components;
|
4022
|
+
const componentsResult = (components2 || []).reduce(
|
4023
|
+
(acc, componentUID) => {
|
4024
|
+
const componentResult = getPopulateForValidation(componentUID);
|
4025
|
+
if (Object.keys(componentResult).length > 0) {
|
4026
|
+
acc[componentUID] = componentResult;
|
4027
|
+
}
|
4028
|
+
return acc;
|
3716
4029
|
},
|
3717
|
-
|
3718
|
-
)
|
3719
|
-
|
4030
|
+
{}
|
4031
|
+
);
|
4032
|
+
if (Object.keys(componentsResult).length > 0) {
|
4033
|
+
populateAcc.populate = populateAcc.populate || {};
|
4034
|
+
populateAcc.populate[attributeName] = { on: componentsResult };
|
4035
|
+
}
|
4036
|
+
}
|
4037
|
+
return populateAcc;
|
3720
4038
|
}, {});
|
3721
4039
|
};
|
3722
4040
|
const getDeepPopulateDraftCount = (uid2) => {
|
@@ -3796,7 +4114,7 @@ const getQueryPopulate = async (uid2, query) => {
|
|
3796
4114
|
return populateQuery;
|
3797
4115
|
};
|
3798
4116
|
const buildDeepPopulate = (uid2) => {
|
3799
|
-
return getService$
|
4117
|
+
return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
|
3800
4118
|
};
|
3801
4119
|
const populateBuilder = (uid2) => {
|
3802
4120
|
let getInitialPopulate = async () => {
|
@@ -3958,7 +4276,6 @@ const AVAILABLE_LOCALES_FIELDS = [
|
|
3958
4276
|
"locale",
|
3959
4277
|
"updatedAt",
|
3960
4278
|
"createdAt",
|
3961
|
-
"status",
|
3962
4279
|
"publishedAt",
|
3963
4280
|
"documentId"
|
3964
4281
|
];
|
@@ -3979,34 +4296,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3979
4296
|
/**
|
3980
4297
|
* Returns available locales of a document for the current status
|
3981
4298
|
*/
|
3982
|
-
async getAvailableLocales(uid2, version, allVersions
|
4299
|
+
async getAvailableLocales(uid2, version, allVersions) {
|
3983
4300
|
const versionsByLocale = groupBy("locale", allVersions);
|
3984
|
-
|
4301
|
+
if (version.locale) {
|
4302
|
+
delete versionsByLocale[version.locale];
|
4303
|
+
}
|
3985
4304
|
const model = strapi2.getModel(uid2);
|
3986
|
-
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
3987
|
-
const traversalFunction = async (localeVersion) => traverseEntity(
|
3988
|
-
({ key }, { remove }) => {
|
3989
|
-
if (keysToKeep.includes(key)) {
|
3990
|
-
return;
|
3991
|
-
}
|
3992
|
-
remove(key);
|
3993
|
-
},
|
3994
|
-
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
3995
|
-
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
3996
|
-
localeVersion
|
3997
|
-
);
|
3998
4305
|
const mappingResult = await async.map(
|
3999
4306
|
Object.values(versionsByLocale),
|
4000
4307
|
async (localeVersions) => {
|
4001
|
-
const mappedLocaleVersions = await async.map(
|
4002
|
-
localeVersions,
|
4003
|
-
traversalFunction
|
4004
|
-
);
|
4005
4308
|
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
4006
|
-
return
|
4309
|
+
return localeVersions[0];
|
4007
4310
|
}
|
4008
|
-
const draftVersion =
|
4009
|
-
const otherVersions =
|
4311
|
+
const draftVersion = localeVersions.find((v) => v.publishedAt === null);
|
4312
|
+
const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
|
4010
4313
|
if (!draftVersion) {
|
4011
4314
|
return;
|
4012
4315
|
}
|
@@ -4028,8 +4331,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4028
4331
|
const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
|
4029
4332
|
return matchLocale && matchStatus;
|
4030
4333
|
});
|
4031
|
-
if (!availableStatus)
|
4032
|
-
return availableStatus;
|
4334
|
+
if (!availableStatus) return availableStatus;
|
4033
4335
|
return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
|
4034
4336
|
},
|
4035
4337
|
/**
|
@@ -4039,18 +4341,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4039
4341
|
* @returns
|
4040
4342
|
*/
|
4041
4343
|
async getManyAvailableStatus(uid2, documents) {
|
4042
|
-
if (!documents.length)
|
4043
|
-
return [];
|
4344
|
+
if (!documents.length) return [];
|
4044
4345
|
const status = documents[0].publishedAt !== null ? "published" : "draft";
|
4045
|
-
const
|
4046
|
-
const
|
4047
|
-
|
4048
|
-
|
4049
|
-
|
4050
|
-
|
4051
|
-
|
4052
|
-
|
4053
|
-
|
4346
|
+
const locales = documents.map((d) => d.locale).filter(Boolean);
|
4347
|
+
const where = {
|
4348
|
+
documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },
|
4349
|
+
publishedAt: { $null: status === "published" }
|
4350
|
+
};
|
4351
|
+
if (locales.length) {
|
4352
|
+
where.locale = { $in: locales };
|
4353
|
+
}
|
4354
|
+
return strapi2.query(uid2).findMany({
|
4355
|
+
where,
|
4356
|
+
select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
|
4054
4357
|
});
|
4055
4358
|
},
|
4056
4359
|
getStatus(version, otherDocumentStatuses) {
|
@@ -4067,10 +4370,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4067
4370
|
} else if (otherVersion) {
|
4068
4371
|
draftVersion = otherVersion;
|
4069
4372
|
}
|
4070
|
-
if (!draftVersion)
|
4071
|
-
|
4072
|
-
if (!publishedVersion)
|
4073
|
-
return CONTENT_MANAGER_STATUS.DRAFT;
|
4373
|
+
if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
|
4374
|
+
if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
|
4074
4375
|
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4075
4376
|
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
4076
4377
|
},
|
@@ -4078,11 +4379,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4078
4379
|
// We could refactor this so the locales are only loaded when they're
|
4079
4380
|
// needed. e.g. in the bulk locale action modal.
|
4080
4381
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4081
|
-
const populate =
|
4082
|
-
const
|
4083
|
-
where: { documentId: version.documentId },
|
4382
|
+
const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
|
4383
|
+
const params = {
|
4084
4384
|
populate: {
|
4085
|
-
// Populate only fields that require validation for bulk locale actions
|
4086
4385
|
...populate,
|
4087
4386
|
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
4088
4387
|
createdBy: {
|
@@ -4091,9 +4390,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4091
4390
|
updatedBy: {
|
4092
4391
|
select: ["id", "firstname", "lastname", "email"]
|
4093
4392
|
}
|
4393
|
+
},
|
4394
|
+
fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
|
4395
|
+
filters: {
|
4396
|
+
documentId: version.documentId
|
4094
4397
|
}
|
4095
|
-
}
|
4096
|
-
const
|
4398
|
+
};
|
4399
|
+
const dbParams = strapi2.get("query-params").transform(uid2, params);
|
4400
|
+
const versions = await strapi2.db.query(uid2).findMany(dbParams);
|
4401
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions) : [];
|
4097
4402
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
4098
4403
|
return {
|
4099
4404
|
availableLocales: availableLocalesResult,
|
@@ -4107,13 +4412,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4107
4412
|
*/
|
4108
4413
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
4109
4414
|
if (!document) {
|
4110
|
-
return
|
4415
|
+
return {
|
4416
|
+
data: document,
|
4417
|
+
meta: {
|
4418
|
+
availableLocales: [],
|
4419
|
+
availableStatus: []
|
4420
|
+
}
|
4421
|
+
};
|
4111
4422
|
}
|
4112
4423
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
4113
4424
|
if (!hasDraftAndPublish) {
|
4114
4425
|
opts.availableStatus = false;
|
4115
4426
|
}
|
4116
4427
|
const meta = await this.getMetadata(uid2, document, opts);
|
4428
|
+
if (document.localizations) {
|
4429
|
+
const otherStatus = await this.getManyAvailableStatus(uid2, document.localizations);
|
4430
|
+
document.localizations = document.localizations.map((d) => {
|
4431
|
+
const status = otherStatus.find((s) => s.documentId === d.documentId);
|
4432
|
+
return {
|
4433
|
+
...d,
|
4434
|
+
status: this.getStatus(d, status ? [status] : [])
|
4435
|
+
};
|
4436
|
+
});
|
4437
|
+
}
|
4117
4438
|
return {
|
4118
4439
|
data: {
|
4119
4440
|
...document,
|
@@ -4331,7 +4652,8 @@ const services = {
|
|
4331
4652
|
permission,
|
4332
4653
|
"populate-builder": populateBuilder$1,
|
4333
4654
|
uid,
|
4334
|
-
...history.services ? history.services : {}
|
4655
|
+
...history.services ? history.services : {},
|
4656
|
+
...preview.services ? preview.services : {}
|
4335
4657
|
};
|
4336
4658
|
const index = () => {
|
4337
4659
|
return {
|