@strapi/content-manager 0.0.0-experimental.826f263c58b6886b849d3f03b81f7a530bc51c91 → 0.0.0-experimental.82afe56cecefd0078d534e25909834ecf5fdd404
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js → ComponentConfigurationPage-DMxUlNOo.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js.map → ComponentConfigurationPage-DMxUlNOo.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs → ComponentConfigurationPage-baEkO-OV.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs.map → ComponentConfigurationPage-baEkO-OV.mjs.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-tDtWj7R2.js → EditConfigurationPage-CXxV7mKn.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js.map → EditConfigurationPage-CXxV7mKn.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs → EditConfigurationPage-YR8-4VCS.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs.map → EditConfigurationPage-YR8-4VCS.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-CoQEnFlC.js → EditViewPage-BfR6jAR6.js} +71 -84
- package/dist/_chunks/EditViewPage-BfR6jAR6.js.map +1 -0
- package/dist/_chunks/EditViewPage-DFF7c27p.mjs +191 -0
- package/dist/_chunks/EditViewPage-DFF7c27p.mjs.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-Bpig5rch.js → Form-CjcMRP5A.js} +55 -38
- package/dist/_chunks/Form-CjcMRP5A.js.map +1 -0
- package/dist/_chunks/{Form-Dxmihyw8.mjs → Form-MSOSfGGN.mjs} +55 -37
- package/dist/_chunks/Form-MSOSfGGN.mjs.map +1 -0
- package/dist/_chunks/{History-BfX6XmZK.js → History-BgZ7gVuF.js} +208 -138
- package/dist/_chunks/History-BgZ7gVuF.js.map +1 -0
- package/dist/_chunks/{History-BZP8n7KT.mjs → History-WOQNVho-.mjs} +201 -130
- package/dist/_chunks/History-WOQNVho-.mjs.map +1 -0
- package/dist/_chunks/{Field-Cz_J9551.mjs → Input-BkKwZ6Qt.mjs} +1757 -1383
- package/dist/_chunks/Input-BkKwZ6Qt.mjs.map +1 -0
- package/dist/_chunks/{Field-ZdrmmQ4Y.js → Input-BwOibhc3.js} +1748 -1374
- package/dist/_chunks/Input-BwOibhc3.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DxKuVkKz.mjs → ListConfigurationPage-BeXfr6uW.mjs} +63 -52
- package/dist/_chunks/ListConfigurationPage-BeXfr6uW.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-B3CXj8PY.js → ListConfigurationPage-DnJ3nbwL.js} +62 -51
- package/dist/_chunks/ListConfigurationPage-DnJ3nbwL.js.map +1 -0
- package/dist/_chunks/{ListViewPage-Bk9VO__I.js → ListViewPage-CJFDudKl.js} +155 -129
- package/dist/_chunks/ListViewPage-CJFDudKl.js.map +1 -0
- package/dist/_chunks/{ListViewPage-D5D3tVPq.mjs → ListViewPage-VK2v44Q1.mjs} +156 -129
- package/dist/_chunks/ListViewPage-VK2v44Q1.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs → NoContentTypePage-T8ttty6K.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs.map → NoContentTypePage-T8ttty6K.mjs.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js → NoContentTypePage-en2PwWgI.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js.map → NoContentTypePage-en2PwWgI.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js → NoPermissionsPage-CcjILry3.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js.map → NoPermissionsPage-CcjILry3.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs → NoPermissionsPage-CokBHhhy.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs.map → NoPermissionsPage-CokBHhhy.mjs.map} +1 -1
- package/dist/_chunks/Preview-BF81YhRj.mjs +287 -0
- package/dist/_chunks/Preview-BF81YhRj.mjs.map +1 -0
- package/dist/_chunks/Preview-DgzAuzWQ.js +305 -0
- package/dist/_chunks/Preview-DgzAuzWQ.js.map +1 -0
- package/dist/_chunks/{Relations-B6B3A3mb.js → Relations-1O-JcM4t.js} +76 -43
- package/dist/_chunks/Relations-1O-JcM4t.js.map +1 -0
- package/dist/_chunks/{Relations-BOYZmuWy.mjs → Relations-BncdhGCd.mjs} +76 -42
- package/dist/_chunks/Relations-BncdhGCd.mjs.map +1 -0
- package/dist/_chunks/{en-Dzv55oQw.mjs → en-BZaUty0m.mjs} +41 -18
- package/dist/_chunks/{en-Dzv55oQw.mjs.map → en-BZaUty0m.mjs.map} +1 -1
- package/dist/_chunks/{en-BN1bvFK7.js → en-CzCnBk4S.js} +41 -18
- package/dist/_chunks/{en-BN1bvFK7.js.map → en-CzCnBk4S.js.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-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-VHviNMeW.mjs → index-DiluOUp6.mjs} +1469 -966
- package/dist/_chunks/index-DiluOUp6.mjs.map +1 -0
- package/dist/_chunks/{index-DzN3kBgx.js → index-EXJvmn4t.js} +1439 -936
- package/dist/_chunks/index-EXJvmn4t.js.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-b91XRlD2.js → layout-4TbKVax8.js} +41 -24
- package/dist/_chunks/layout-4TbKVax8.js.map +1 -0
- package/dist/_chunks/{layout-CPn1PM6x.mjs → layout-mSwsYzxv.mjs} +42 -24
- package/dist/_chunks/layout-mSwsYzxv.mjs.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-BsqxS6tR.mjs → relations--YOvQBqv.mjs} +6 -7
- package/dist/_chunks/relations--YOvQBqv.mjs.map +1 -0
- package/dist/_chunks/{relations-CA7IYmcP.js → relations-Ai6Izh7h.js} +6 -7
- package/dist/_chunks/relations-Ai6Izh7h.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-CZGy2Vjf.mjs +29 -0
- package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
- package/dist/_chunks/{usePrev-B9w_-eYc.js → usePrev-D5J_2fEu.js} +14 -1
- package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +10 -8
- package/dist/admin/src/content-manager.d.ts +3 -2
- package/dist/admin/src/exports.d.ts +2 -1
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +49 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +9 -4
- 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 +5 -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/Relations.d.ts +20 -0
- 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 +6 -58
- 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/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- package/dist/admin/src/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 +765 -434
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +766 -434
- 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/uid.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/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.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-CoQEnFlC.js.map +0 -1
- package/dist/_chunks/EditViewPage-DvaV7U9b.mjs +0 -203
- package/dist/_chunks/EditViewPage-DvaV7U9b.mjs.map +0 -1
- package/dist/_chunks/Field-Cz_J9551.mjs.map +0 -1
- package/dist/_chunks/Field-ZdrmmQ4Y.js.map +0 -1
- package/dist/_chunks/Form-Bpig5rch.js.map +0 -1
- package/dist/_chunks/Form-Dxmihyw8.mjs.map +0 -1
- package/dist/_chunks/History-BZP8n7KT.mjs.map +0 -1
- package/dist/_chunks/History-BfX6XmZK.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-B3CXj8PY.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DxKuVkKz.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-Bk9VO__I.js.map +0 -1
- package/dist/_chunks/ListViewPage-D5D3tVPq.mjs.map +0 -1
- package/dist/_chunks/Relations-B6B3A3mb.js.map +0 -1
- package/dist/_chunks/Relations-BOYZmuWy.mjs.map +0 -1
- package/dist/_chunks/index-DzN3kBgx.js.map +0 -1
- package/dist/_chunks/index-VHviNMeW.mjs.map +0 -1
- package/dist/_chunks/layout-CPn1PM6x.mjs.map +0 -1
- package/dist/_chunks/layout-b91XRlD2.js.map +0 -1
- package/dist/_chunks/relations-BsqxS6tR.mjs.map +0 -1
- package/dist/_chunks/relations-CA7IYmcP.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.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,31 +197,53 @@ 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": {
|
218
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
219
|
+
if (isMorphRelation) {
|
220
|
+
break;
|
221
|
+
}
|
209
222
|
const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
|
210
223
|
if (isVisible2) {
|
211
|
-
acc[attributeName] = {
|
224
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
212
225
|
}
|
213
226
|
break;
|
214
227
|
}
|
215
228
|
case "media": {
|
216
|
-
acc[attributeName] = {
|
229
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
217
230
|
break;
|
218
231
|
}
|
219
232
|
case "component": {
|
220
233
|
const populate = getDeepPopulate2(attribute.component);
|
221
|
-
acc[attributeName] = {
|
234
|
+
acc[attributeName] = {
|
235
|
+
populate,
|
236
|
+
[fieldSelector]: getComponentFields(attribute.component)
|
237
|
+
};
|
222
238
|
break;
|
223
239
|
}
|
224
240
|
case "dynamiczone": {
|
225
241
|
const populatedComponents = (attribute.components || []).reduce(
|
226
242
|
(acc2, componentUID) => {
|
227
|
-
acc2[componentUID] = {
|
243
|
+
acc2[componentUID] = {
|
244
|
+
populate: getDeepPopulate2(componentUID),
|
245
|
+
[fieldSelector]: getComponentFields(componentUID)
|
246
|
+
};
|
228
247
|
return acc2;
|
229
248
|
},
|
230
249
|
{}
|
@@ -286,6 +305,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
286
305
|
getRelationRestoreValue,
|
287
306
|
getMediaRestoreValue,
|
288
307
|
getDefaultLocale,
|
308
|
+
isLocalizedContentType,
|
289
309
|
getLocaleDictionary,
|
290
310
|
getRetentionDays,
|
291
311
|
getVersionStatus,
|
@@ -308,7 +328,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
308
328
|
});
|
309
329
|
},
|
310
330
|
async findVersionsPage(params) {
|
311
|
-
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
|
+
}
|
312
338
|
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
313
339
|
query.findPage({
|
314
340
|
...params.query,
|
@@ -324,78 +350,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
324
350
|
}),
|
325
351
|
serviceUtils.getLocaleDictionary()
|
326
352
|
]);
|
327
|
-
const
|
328
|
-
|
329
|
-
async (
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
model: "plugin::upload.file"
|
336
|
-
});
|
337
|
-
const response = await serviceUtils.buildMediaResponse(attributeValues);
|
338
|
-
const sanitizedResults = await Promise.all(
|
339
|
-
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
340
|
-
);
|
341
|
-
return {
|
342
|
-
...await currentDataWithRelations,
|
343
|
-
[attributeKey]: {
|
344
|
-
results: sanitizedResults,
|
345
|
-
meta: response.meta
|
346
|
-
}
|
347
|
-
};
|
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");
|
348
361
|
}
|
349
|
-
if (
|
350
|
-
|
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") {
|
351
365
|
const adminUsers = await Promise.all(
|
352
|
-
|
366
|
+
currentValue.map((userToPopulate) => {
|
353
367
|
if (userToPopulate == null) {
|
354
368
|
return null;
|
355
369
|
}
|
356
|
-
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
|
+
});
|
357
376
|
})
|
358
377
|
);
|
359
|
-
|
360
|
-
...await currentDataWithRelations,
|
361
|
-
/**
|
362
|
-
* Ideally we would return the same "{results: [], meta: {}}" shape, however,
|
363
|
-
* when sanitizing the data as a whole in the controller before sending to the client,
|
364
|
-
* the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
|
365
|
-
*/
|
366
|
-
[attributeKey]: adminUsers
|
367
|
-
};
|
378
|
+
utils.set(options.key, adminUsers);
|
368
379
|
}
|
369
|
-
const permissionChecker2 = getService$
|
380
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
370
381
|
userAbility: params.state.userAbility,
|
371
|
-
model:
|
382
|
+
model: options.attribute.target
|
372
383
|
});
|
373
384
|
const response = await serviceUtils.buildRelationReponse(
|
374
|
-
|
375
|
-
|
385
|
+
currentValue,
|
386
|
+
options.attribute
|
376
387
|
);
|
377
388
|
const sanitizedResults = await Promise.all(
|
378
389
|
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
379
390
|
);
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
meta: response.meta
|
385
|
-
}
|
386
|
-
};
|
391
|
+
utils.set(options.key, {
|
392
|
+
results: sanitizedResults,
|
393
|
+
meta: response.meta
|
394
|
+
});
|
387
395
|
}
|
388
|
-
|
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)
|
389
414
|
},
|
390
|
-
|
415
|
+
entry.data
|
391
416
|
);
|
392
|
-
return entryWithRelations;
|
393
417
|
};
|
394
418
|
const formattedResults = await Promise.all(
|
395
419
|
results.map(async (result) => {
|
396
420
|
return {
|
397
421
|
...result,
|
398
|
-
data: await
|
422
|
+
data: await populateEntry(result),
|
399
423
|
meta: {
|
400
424
|
unknownAttributes: serviceUtils.getSchemaAttributesDiff(
|
401
425
|
result.schema,
|
@@ -426,30 +450,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
426
450
|
// Clone to avoid mutating the original version data
|
427
451
|
structuredClone(version.data)
|
428
452
|
);
|
429
|
-
const
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
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
|
+
}
|
439
463
|
}
|
440
|
-
if (attribute.type === "
|
441
|
-
|
442
|
-
|
443
|
-
|
464
|
+
if (options.attribute.type === "dynamiczone") {
|
465
|
+
if (options.value === null) {
|
466
|
+
utils.set(options.key, []);
|
467
|
+
}
|
444
468
|
}
|
445
|
-
if (attribute.type === "
|
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);
|
477
|
+
}
|
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);
|
448
484
|
}
|
449
|
-
return previousRelationAttributes;
|
450
485
|
},
|
451
|
-
|
452
|
-
|
486
|
+
{
|
487
|
+
schema,
|
488
|
+
getModel: strapi2.getModel.bind(strapi2)
|
489
|
+
},
|
490
|
+
dataWithoutAddedAttributes
|
453
491
|
);
|
454
492
|
const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
|
455
493
|
const restoredDocument = await strapi2.documents(version.contentType).update({
|
@@ -464,13 +502,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
464
502
|
}
|
465
503
|
};
|
466
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
|
+
};
|
467
541
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
468
542
|
const state = {
|
469
543
|
deleteExpiredJob: null,
|
470
544
|
isInitialized: false
|
471
545
|
};
|
472
|
-
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
473
|
-
const historyService = getService(strapi2, "history");
|
474
546
|
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
475
547
|
return {
|
476
548
|
async bootstrap() {
|
@@ -478,73 +550,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
478
550
|
return;
|
479
551
|
}
|
480
552
|
strapi2.documents.use(async (context, next) => {
|
481
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
482
|
-
return next();
|
483
|
-
}
|
484
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
485
|
-
return next();
|
486
|
-
}
|
487
|
-
const contentTypeUid = context.contentType.uid;
|
488
|
-
if (!contentTypeUid.startsWith("api::")) {
|
489
|
-
return next();
|
490
|
-
}
|
491
553
|
const result = await next();
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
554
|
+
if (!shouldCreateHistoryVersion(context)) {
|
555
|
+
return result;
|
556
|
+
}
|
557
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
496
558
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
497
|
-
const
|
498
|
-
if (
|
499
|
-
|
500
|
-
"[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
|
501
|
-
);
|
502
|
-
return next();
|
559
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
560
|
+
if (!locales.length) {
|
561
|
+
return result;
|
503
562
|
}
|
504
|
-
const
|
505
|
-
|
506
|
-
|
507
|
-
|
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
|
+
)
|
508
578
|
});
|
509
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
510
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
511
|
-
const componentsSchemas = Object.keys(
|
512
|
-
attributesSchema
|
513
|
-
).reduce((currentComponentSchemas, key) => {
|
514
|
-
const fieldSchema = attributesSchema[key];
|
515
|
-
if (fieldSchema.type === "component") {
|
516
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
517
|
-
return {
|
518
|
-
...currentComponentSchemas,
|
519
|
-
[fieldSchema.component]: componentSchema
|
520
|
-
};
|
521
|
-
}
|
522
|
-
return currentComponentSchemas;
|
523
|
-
}, {});
|
524
579
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
525
|
-
onCommit(() => {
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
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
|
+
}
|
535
592
|
});
|
536
593
|
});
|
537
594
|
return result;
|
538
595
|
});
|
539
|
-
state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
|
596
|
+
state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
|
540
597
|
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
541
598
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
542
|
-
query.deleteMany({
|
599
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
543
600
|
where: {
|
544
601
|
created_at: {
|
545
|
-
$lt: expirationDate
|
602
|
+
$lt: expirationDate
|
546
603
|
}
|
547
604
|
}
|
605
|
+
}).catch((error) => {
|
606
|
+
if (error instanceof Error) {
|
607
|
+
strapi2.log.error("Error deleting expired history versions", error.message);
|
608
|
+
}
|
548
609
|
});
|
549
610
|
});
|
550
611
|
state.isInitialized = true;
|
@@ -556,17 +617,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
556
617
|
}
|
557
618
|
};
|
558
619
|
};
|
559
|
-
const services$
|
620
|
+
const services$2 = {
|
560
621
|
history: createHistoryService,
|
561
622
|
lifecycles: createLifecyclesService
|
562
623
|
};
|
563
|
-
const info = { pluginName: "content-manager", type: "admin" };
|
624
|
+
const info$1 = { pluginName: "content-manager", type: "admin" };
|
564
625
|
const historyVersionRouter = {
|
565
626
|
type: "admin",
|
566
627
|
routes: [
|
567
628
|
{
|
568
629
|
method: "GET",
|
569
|
-
info,
|
630
|
+
info: info$1,
|
570
631
|
path: "/history-versions",
|
571
632
|
handler: "history-version.findMany",
|
572
633
|
config: {
|
@@ -575,7 +636,7 @@ const historyVersionRouter = {
|
|
575
636
|
},
|
576
637
|
{
|
577
638
|
method: "PUT",
|
578
|
-
info,
|
639
|
+
info: info$1,
|
579
640
|
path: "/history-versions/:versionId/restore",
|
580
641
|
handler: "history-version.restoreVersion",
|
581
642
|
config: {
|
@@ -584,7 +645,7 @@ const historyVersionRouter = {
|
|
584
645
|
}
|
585
646
|
]
|
586
647
|
};
|
587
|
-
const routes$
|
648
|
+
const routes$2 = {
|
588
649
|
"history-version": historyVersionRouter
|
589
650
|
};
|
590
651
|
const historyVersion = {
|
@@ -631,21 +692,21 @@ const historyVersion = {
|
|
631
692
|
}
|
632
693
|
}
|
633
694
|
};
|
634
|
-
const getFeature = () => {
|
695
|
+
const getFeature$1 = () => {
|
635
696
|
if (strapi.ee.features.isEnabled("cms-content-history")) {
|
636
697
|
return {
|
637
698
|
register({ strapi: strapi2 }) {
|
638
699
|
strapi2.get("models").add(historyVersion);
|
639
700
|
},
|
640
701
|
bootstrap({ strapi: strapi2 }) {
|
641
|
-
getService(strapi2, "lifecycles").bootstrap();
|
702
|
+
getService$1(strapi2, "lifecycles").bootstrap();
|
642
703
|
},
|
643
704
|
destroy({ strapi: strapi2 }) {
|
644
|
-
getService(strapi2, "lifecycles").destroy();
|
705
|
+
getService$1(strapi2, "lifecycles").destroy();
|
645
706
|
},
|
646
|
-
controllers: controllers$
|
647
|
-
services: services$
|
648
|
-
routes: routes$
|
707
|
+
controllers: controllers$2,
|
708
|
+
services: services$2,
|
709
|
+
routes: routes$2
|
649
710
|
};
|
650
711
|
}
|
651
712
|
return {
|
@@ -654,9 +715,201 @@ const getFeature = () => {
|
|
654
715
|
}
|
655
716
|
};
|
656
717
|
};
|
657
|
-
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();
|
658
910
|
const register = async ({ strapi: strapi2 }) => {
|
659
911
|
await history.register?.({ strapi: strapi2 });
|
912
|
+
await preview.register?.({ strapi: strapi2 });
|
660
913
|
};
|
661
914
|
const ALLOWED_WEBHOOK_EVENTS = {
|
662
915
|
ENTRY_PUBLISH: "entry.publish",
|
@@ -666,11 +919,12 @@ const bootstrap = async () => {
|
|
666
919
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
667
920
|
strapi.get("webhookStore").addAllowedEvent(key, value);
|
668
921
|
});
|
669
|
-
getService$
|
670
|
-
await getService$
|
671
|
-
await getService$
|
672
|
-
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();
|
673
926
|
await history.bootstrap?.({ strapi });
|
927
|
+
await preview.bootstrap?.({ strapi });
|
674
928
|
};
|
675
929
|
const destroy = async ({ strapi: strapi2 }) => {
|
676
930
|
await history.destroy?.({ strapi: strapi2 });
|
@@ -1160,7 +1414,8 @@ const admin = {
|
|
1160
1414
|
};
|
1161
1415
|
const routes = {
|
1162
1416
|
admin,
|
1163
|
-
...history.routes ? history.routes : {}
|
1417
|
+
...history.routes ? history.routes : {},
|
1418
|
+
...preview.routes ? preview.routes : {}
|
1164
1419
|
};
|
1165
1420
|
const hasPermissionsSchema = yup$1.object({
|
1166
1421
|
actions: yup$1.array().of(yup$1.string()),
|
@@ -1171,6 +1426,11 @@ const { createPolicy } = policy;
|
|
1171
1426
|
const hasPermissions = createPolicy({
|
1172
1427
|
name: "plugin::content-manager.hasPermissions",
|
1173
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
|
+
*/
|
1174
1434
|
handler(ctx, config = {}) {
|
1175
1435
|
const { actions = [], hasAtLeastOne = false } = config;
|
1176
1436
|
const { userAbility } = ctx.state;
|
@@ -1218,8 +1478,7 @@ const isSortable = (schema, name) => {
|
|
1218
1478
|
if (!_.has(schema.attributes, name)) {
|
1219
1479
|
return false;
|
1220
1480
|
}
|
1221
|
-
if (schema.modelType === "component" && name === "id")
|
1222
|
-
return false;
|
1481
|
+
if (schema.modelType === "component" && name === "id") return false;
|
1223
1482
|
const attribute = schema.attributes[name];
|
1224
1483
|
if (NON_SORTABLES.includes(attribute.type)) {
|
1225
1484
|
return false;
|
@@ -1364,8 +1623,7 @@ const createDefaultSettings = async (schema) => {
|
|
1364
1623
|
};
|
1365
1624
|
};
|
1366
1625
|
const syncSettings = async (configuration, schema) => {
|
1367
|
-
if (isEmpty(configuration.settings))
|
1368
|
-
return createDefaultSettings(schema);
|
1626
|
+
if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
|
1369
1627
|
const defaultField = getDefaultMainField(schema);
|
1370
1628
|
const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
|
1371
1629
|
return {
|
@@ -1412,7 +1670,7 @@ const createMetadasSchema = (schema) => {
|
|
1412
1670
|
if (!value) {
|
1413
1671
|
return yup$1.string();
|
1414
1672
|
}
|
1415
|
-
const targetSchema = getService$
|
1673
|
+
const targetSchema = getService$2("content-types").findContentType(
|
1416
1674
|
schema.attributes[key].targetModel
|
1417
1675
|
);
|
1418
1676
|
if (!targetSchema) {
|
@@ -1541,8 +1799,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1541
1799
|
}
|
1542
1800
|
switch (attribute.type) {
|
1543
1801
|
case "relation": {
|
1544
|
-
if (canCreate(attributePath))
|
1545
|
-
return body2;
|
1802
|
+
if (canCreate(attributePath)) return body2;
|
1546
1803
|
return set(attributePath, { set: [] }, body2);
|
1547
1804
|
}
|
1548
1805
|
case "component": {
|
@@ -1552,8 +1809,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1552
1809
|
]);
|
1553
1810
|
}
|
1554
1811
|
default: {
|
1555
|
-
if (canCreate(attributePath))
|
1556
|
-
return body2;
|
1812
|
+
if (canCreate(attributePath)) return body2;
|
1557
1813
|
return set(attributePath, null, body2);
|
1558
1814
|
}
|
1559
1815
|
}
|
@@ -1564,9 +1820,11 @@ const multipleLocaleSchema = yup$1.lazy(
|
|
1564
1820
|
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1565
1821
|
);
|
1566
1822
|
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1567
|
-
const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
|
1823
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1568
1824
|
const { allowMultipleLocales } = opts;
|
1569
|
-
const { locale, status, ...rest } = request || {};
|
1825
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1826
|
+
const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1827
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1570
1828
|
const schema = yup$1.object().shape({
|
1571
1829
|
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1572
1830
|
status: statusSchema
|
@@ -1579,7 +1837,7 @@ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales
|
|
1579
1837
|
}
|
1580
1838
|
};
|
1581
1839
|
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1582
|
-
const documentMetadata2 = getService$
|
1840
|
+
const documentMetadata2 = getService$2("document-metadata");
|
1583
1841
|
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1584
1842
|
let {
|
1585
1843
|
meta: { availableLocales, availableStatus }
|
@@ -1605,8 +1863,8 @@ const createDocument = async (ctx, opts) => {
|
|
1605
1863
|
const { userAbility, user } = ctx.state;
|
1606
1864
|
const { model } = ctx.params;
|
1607
1865
|
const { body } = ctx.request;
|
1608
|
-
const documentManager2 = getService$
|
1609
|
-
const permissionChecker2 = getService$
|
1866
|
+
const documentManager2 = getService$2("document-manager");
|
1867
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1610
1868
|
if (permissionChecker2.cannot.create()) {
|
1611
1869
|
throw new errors.ForbiddenError();
|
1612
1870
|
}
|
@@ -1614,7 +1872,7 @@ const createDocument = async (ctx, opts) => {
|
|
1614
1872
|
const setCreator = setCreatorFields({ user });
|
1615
1873
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1616
1874
|
const sanitizedBody = await sanitizeFn(body);
|
1617
|
-
const { locale, status
|
1875
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1618
1876
|
return documentManager2.create(model, {
|
1619
1877
|
data: sanitizedBody,
|
1620
1878
|
locale,
|
@@ -1626,14 +1884,14 @@ const updateDocument = async (ctx, opts) => {
|
|
1626
1884
|
const { userAbility, user } = ctx.state;
|
1627
1885
|
const { id, model } = ctx.params;
|
1628
1886
|
const { body } = ctx.request;
|
1629
|
-
const documentManager2 = getService$
|
1630
|
-
const permissionChecker2 = getService$
|
1887
|
+
const documentManager2 = getService$2("document-manager");
|
1888
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1631
1889
|
if (permissionChecker2.cannot.update()) {
|
1632
1890
|
throw new errors.ForbiddenError();
|
1633
1891
|
}
|
1634
1892
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1635
|
-
const populate = await getService$
|
1636
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1893
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1894
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1637
1895
|
const [documentVersion, documentExists] = await Promise.all([
|
1638
1896
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1639
1897
|
documentManager2.exists(model, id)
|
@@ -1649,7 +1907,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1649
1907
|
throw new errors.ForbiddenError();
|
1650
1908
|
}
|
1651
1909
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1652
|
-
const setCreator = setCreatorFields({ user, isEdition: true });
|
1910
|
+
const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
|
1653
1911
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1654
1912
|
const sanitizedBody = await sanitizeFn(body);
|
1655
1913
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1663,15 +1921,15 @@ const collectionTypes = {
|
|
1663
1921
|
const { userAbility } = ctx.state;
|
1664
1922
|
const { model } = ctx.params;
|
1665
1923
|
const { query } = ctx.request;
|
1666
|
-
const documentMetadata2 = getService$
|
1667
|
-
const documentManager2 = getService$
|
1668
|
-
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 });
|
1669
1927
|
if (permissionChecker2.cannot.read()) {
|
1670
1928
|
return ctx.forbidden();
|
1671
1929
|
}
|
1672
1930
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1673
|
-
const populate = await getService$
|
1674
|
-
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
1931
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1932
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1675
1933
|
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1676
1934
|
{ ...permissionQuery, populate, locale, status },
|
1677
1935
|
model
|
@@ -1699,14 +1957,14 @@ const collectionTypes = {
|
|
1699
1957
|
async findOne(ctx) {
|
1700
1958
|
const { userAbility } = ctx.state;
|
1701
1959
|
const { model, id } = ctx.params;
|
1702
|
-
const documentManager2 = getService$
|
1703
|
-
const permissionChecker2 = getService$
|
1960
|
+
const documentManager2 = getService$2("document-manager");
|
1961
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1704
1962
|
if (permissionChecker2.cannot.read()) {
|
1705
1963
|
return ctx.forbidden();
|
1706
1964
|
}
|
1707
1965
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1708
|
-
const populate = await getService$
|
1709
|
-
const { locale, status
|
1966
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1967
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1710
1968
|
const version = await documentManager2.findOne(id, model, {
|
1711
1969
|
populate,
|
1712
1970
|
locale,
|
@@ -1721,7 +1979,7 @@ const collectionTypes = {
|
|
1721
1979
|
permissionChecker2,
|
1722
1980
|
model,
|
1723
1981
|
// @ts-expect-error TODO: fix
|
1724
|
-
{ id, locale, publishedAt: null },
|
1982
|
+
{ documentId: id, locale, publishedAt: null },
|
1725
1983
|
{ availableLocales: true, availableStatus: false }
|
1726
1984
|
);
|
1727
1985
|
ctx.body = { data: {}, meta };
|
@@ -1736,7 +1994,7 @@ const collectionTypes = {
|
|
1736
1994
|
async create(ctx) {
|
1737
1995
|
const { userAbility } = ctx.state;
|
1738
1996
|
const { model } = ctx.params;
|
1739
|
-
const permissionChecker2 = getService$
|
1997
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1740
1998
|
const [totalEntries, document] = await Promise.all([
|
1741
1999
|
strapi.db.query(model).count(),
|
1742
2000
|
createDocument(ctx)
|
@@ -1757,7 +2015,7 @@ const collectionTypes = {
|
|
1757
2015
|
async update(ctx) {
|
1758
2016
|
const { userAbility } = ctx.state;
|
1759
2017
|
const { model } = ctx.params;
|
1760
|
-
const permissionChecker2 = getService$
|
2018
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1761
2019
|
const updatedVersion = await updateDocument(ctx);
|
1762
2020
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1763
2021
|
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
@@ -1766,14 +2024,14 @@ const collectionTypes = {
|
|
1766
2024
|
const { userAbility, user } = ctx.state;
|
1767
2025
|
const { model, sourceId: id } = ctx.params;
|
1768
2026
|
const { body } = ctx.request;
|
1769
|
-
const documentManager2 = getService$
|
1770
|
-
const permissionChecker2 = getService$
|
2027
|
+
const documentManager2 = getService$2("document-manager");
|
2028
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1771
2029
|
if (permissionChecker2.cannot.create()) {
|
1772
2030
|
return ctx.forbidden();
|
1773
2031
|
}
|
1774
2032
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1775
|
-
const populate = await getService$
|
1776
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2033
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2034
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1777
2035
|
const document = await documentManager2.findOne(id, model, {
|
1778
2036
|
populate,
|
1779
2037
|
locale,
|
@@ -1811,14 +2069,14 @@ const collectionTypes = {
|
|
1811
2069
|
async delete(ctx) {
|
1812
2070
|
const { userAbility } = ctx.state;
|
1813
2071
|
const { id, model } = ctx.params;
|
1814
|
-
const documentManager2 = getService$
|
1815
|
-
const permissionChecker2 = getService$
|
2072
|
+
const documentManager2 = getService$2("document-manager");
|
2073
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1816
2074
|
if (permissionChecker2.cannot.delete()) {
|
1817
2075
|
return ctx.forbidden();
|
1818
2076
|
}
|
1819
2077
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1820
|
-
const populate = await getService$
|
1821
|
-
const { locale } = await getDocumentLocaleAndStatus(ctx.query);
|
2078
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2079
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1822
2080
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1823
2081
|
if (documentLocales.length === 0) {
|
1824
2082
|
return ctx.notFound();
|
@@ -1839,19 +2097,42 @@ const collectionTypes = {
|
|
1839
2097
|
const { userAbility } = ctx.state;
|
1840
2098
|
const { id, model } = ctx.params;
|
1841
2099
|
const { body } = ctx.request;
|
1842
|
-
const documentManager2 = getService$
|
1843
|
-
const permissionChecker2 = getService$
|
2100
|
+
const documentManager2 = getService$2("document-manager");
|
2101
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1844
2102
|
if (permissionChecker2.cannot.publish()) {
|
1845
2103
|
return ctx.forbidden();
|
1846
2104
|
}
|
1847
2105
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1848
2106
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1849
|
-
const populate = await getService$
|
1850
|
-
|
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
|
+
}
|
1851
2133
|
if (permissionChecker2.cannot.publish(document)) {
|
1852
2134
|
throw new errors.ForbiddenError();
|
1853
2135
|
}
|
1854
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1855
2136
|
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1856
2137
|
locale
|
1857
2138
|
// TODO: Allow setting creator fields on publish
|
@@ -1871,14 +2152,16 @@ const collectionTypes = {
|
|
1871
2152
|
const { body } = ctx.request;
|
1872
2153
|
const { documentIds } = body;
|
1873
2154
|
await validateBulkActionInput(body);
|
1874
|
-
const documentManager2 = getService$
|
1875
|
-
const permissionChecker2 = getService$
|
2155
|
+
const documentManager2 = getService$2("document-manager");
|
2156
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1876
2157
|
if (permissionChecker2.cannot.publish()) {
|
1877
2158
|
return ctx.forbidden();
|
1878
2159
|
}
|
1879
2160
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1880
|
-
const populate = await getService$
|
1881
|
-
const { locale } = await getDocumentLocaleAndStatus(body, {
|
2161
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
2162
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2163
|
+
allowMultipleLocales: true
|
2164
|
+
});
|
1882
2165
|
const entityPromises = documentIds.map(
|
1883
2166
|
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1884
2167
|
);
|
@@ -1900,12 +2183,14 @@ const collectionTypes = {
|
|
1900
2183
|
const { body } = ctx.request;
|
1901
2184
|
const { documentIds } = body;
|
1902
2185
|
await validateBulkActionInput(body);
|
1903
|
-
const documentManager2 = getService$
|
1904
|
-
const permissionChecker2 = getService$
|
2186
|
+
const documentManager2 = getService$2("document-manager");
|
2187
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1905
2188
|
if (permissionChecker2.cannot.unpublish()) {
|
1906
2189
|
return ctx.forbidden();
|
1907
2190
|
}
|
1908
|
-
const { locale } = await getDocumentLocaleAndStatus(body
|
2191
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2192
|
+
allowMultipleLocales: true
|
2193
|
+
});
|
1909
2194
|
const entityPromises = documentIds.map(
|
1910
2195
|
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1911
2196
|
);
|
@@ -1928,8 +2213,8 @@ const collectionTypes = {
|
|
1928
2213
|
const {
|
1929
2214
|
body: { discardDraft, ...body }
|
1930
2215
|
} = ctx.request;
|
1931
|
-
const documentManager2 = getService$
|
1932
|
-
const permissionChecker2 = getService$
|
2216
|
+
const documentManager2 = getService$2("document-manager");
|
2217
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1933
2218
|
if (permissionChecker2.cannot.unpublish()) {
|
1934
2219
|
return ctx.forbidden();
|
1935
2220
|
}
|
@@ -1937,8 +2222,8 @@ const collectionTypes = {
|
|
1937
2222
|
return ctx.forbidden();
|
1938
2223
|
}
|
1939
2224
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1940
|
-
const populate = await getService$
|
1941
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2225
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2226
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1942
2227
|
const document = await documentManager2.findOne(id, model, {
|
1943
2228
|
populate,
|
1944
2229
|
locale,
|
@@ -1968,14 +2253,14 @@ const collectionTypes = {
|
|
1968
2253
|
const { userAbility } = ctx.state;
|
1969
2254
|
const { id, model } = ctx.params;
|
1970
2255
|
const { body } = ctx.request;
|
1971
|
-
const documentManager2 = getService$
|
1972
|
-
const permissionChecker2 = getService$
|
2256
|
+
const documentManager2 = getService$2("document-manager");
|
2257
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1973
2258
|
if (permissionChecker2.cannot.discard()) {
|
1974
2259
|
return ctx.forbidden();
|
1975
2260
|
}
|
1976
2261
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1977
|
-
const populate = await getService$
|
1978
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2262
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2263
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1979
2264
|
const document = await documentManager2.findOne(id, model, {
|
1980
2265
|
populate,
|
1981
2266
|
locale,
|
@@ -1999,14 +2284,14 @@ const collectionTypes = {
|
|
1999
2284
|
const { query, body } = ctx.request;
|
2000
2285
|
const { documentIds } = body;
|
2001
2286
|
await validateBulkActionInput(body);
|
2002
|
-
const documentManager2 = getService$
|
2003
|
-
const permissionChecker2 = getService$
|
2287
|
+
const documentManager2 = getService$2("document-manager");
|
2288
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2004
2289
|
if (permissionChecker2.cannot.delete()) {
|
2005
2290
|
return ctx.forbidden();
|
2006
2291
|
}
|
2007
2292
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2008
|
-
const populate = await getService$
|
2009
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2293
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2294
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2010
2295
|
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2011
2296
|
populate,
|
2012
2297
|
locale
|
@@ -2026,14 +2311,14 @@ const collectionTypes = {
|
|
2026
2311
|
async countDraftRelations(ctx) {
|
2027
2312
|
const { userAbility } = ctx.state;
|
2028
2313
|
const { model, id } = ctx.params;
|
2029
|
-
const documentManager2 = getService$
|
2030
|
-
const permissionChecker2 = getService$
|
2314
|
+
const documentManager2 = getService$2("document-manager");
|
2315
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2031
2316
|
if (permissionChecker2.cannot.read()) {
|
2032
2317
|
return ctx.forbidden();
|
2033
2318
|
}
|
2034
2319
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2035
|
-
const populate = await getService$
|
2036
|
-
const { locale, status
|
2320
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2321
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
2037
2322
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
2038
2323
|
if (!entity) {
|
2039
2324
|
return ctx.notFound();
|
@@ -2051,12 +2336,12 @@ const collectionTypes = {
|
|
2051
2336
|
const ids = ctx.request.query.documentIds;
|
2052
2337
|
const locale = ctx.request.query.locale;
|
2053
2338
|
const { model } = ctx.params;
|
2054
|
-
const documentManager2 = getService$
|
2055
|
-
const permissionChecker2 = getService$
|
2339
|
+
const documentManager2 = getService$2("document-manager");
|
2340
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2056
2341
|
if (permissionChecker2.cannot.read()) {
|
2057
2342
|
return ctx.forbidden();
|
2058
2343
|
}
|
2059
|
-
const
|
2344
|
+
const documents = await documentManager2.findMany(
|
2060
2345
|
{
|
2061
2346
|
filters: {
|
2062
2347
|
documentId: ids
|
@@ -2065,7 +2350,7 @@ const collectionTypes = {
|
|
2065
2350
|
},
|
2066
2351
|
model
|
2067
2352
|
);
|
2068
|
-
if (!
|
2353
|
+
if (!documents) {
|
2069
2354
|
return ctx.notFound();
|
2070
2355
|
}
|
2071
2356
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2076,13 +2361,13 @@ const collectionTypes = {
|
|
2076
2361
|
};
|
2077
2362
|
const components$1 = {
|
2078
2363
|
findComponents(ctx) {
|
2079
|
-
const components2 = getService$
|
2080
|
-
const { toDto } = getService$
|
2364
|
+
const components2 = getService$2("components").findAllComponents();
|
2365
|
+
const { toDto } = getService$2("data-mapper");
|
2081
2366
|
ctx.body = { data: components2.map(toDto) };
|
2082
2367
|
},
|
2083
2368
|
async findComponentConfiguration(ctx) {
|
2084
2369
|
const { uid: uid2 } = ctx.params;
|
2085
|
-
const componentService = getService$
|
2370
|
+
const componentService = getService$2("components");
|
2086
2371
|
const component = componentService.findComponent(uid2);
|
2087
2372
|
if (!component) {
|
2088
2373
|
return ctx.notFound("component.notFound");
|
@@ -2099,7 +2384,7 @@ const components$1 = {
|
|
2099
2384
|
async updateComponentConfiguration(ctx) {
|
2100
2385
|
const { uid: uid2 } = ctx.params;
|
2101
2386
|
const { body } = ctx.request;
|
2102
|
-
const componentService = getService$
|
2387
|
+
const componentService = getService$2("components");
|
2103
2388
|
const component = componentService.findComponent(uid2);
|
2104
2389
|
if (!component) {
|
2105
2390
|
return ctx.notFound("component.notFound");
|
@@ -2133,12 +2418,12 @@ const contentTypes = {
|
|
2133
2418
|
} catch (error) {
|
2134
2419
|
return ctx.send({ error }, 400);
|
2135
2420
|
}
|
2136
|
-
const contentTypes2 = getService$
|
2137
|
-
const { toDto } = getService$
|
2421
|
+
const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
|
2422
|
+
const { toDto } = getService$2("data-mapper");
|
2138
2423
|
ctx.body = { data: contentTypes2.map(toDto) };
|
2139
2424
|
},
|
2140
2425
|
async findContentTypesSettings(ctx) {
|
2141
|
-
const { findAllContentTypes, findConfiguration } = getService$
|
2426
|
+
const { findAllContentTypes, findConfiguration } = getService$2("content-types");
|
2142
2427
|
const contentTypes2 = await findAllContentTypes();
|
2143
2428
|
const configurations = await Promise.all(
|
2144
2429
|
contentTypes2.map(async (contentType) => {
|
@@ -2152,7 +2437,7 @@ const contentTypes = {
|
|
2152
2437
|
},
|
2153
2438
|
async findContentTypeConfiguration(ctx) {
|
2154
2439
|
const { uid: uid2 } = ctx.params;
|
2155
|
-
const contentTypeService = getService$
|
2440
|
+
const contentTypeService = getService$2("content-types");
|
2156
2441
|
const contentType = await contentTypeService.findContentType(uid2);
|
2157
2442
|
if (!contentType) {
|
2158
2443
|
return ctx.notFound("contentType.notFound");
|
@@ -2174,13 +2459,13 @@ const contentTypes = {
|
|
2174
2459
|
const { userAbility } = ctx.state;
|
2175
2460
|
const { uid: uid2 } = ctx.params;
|
2176
2461
|
const { body } = ctx.request;
|
2177
|
-
const contentTypeService = getService$
|
2178
|
-
const metricsService = getService$
|
2462
|
+
const contentTypeService = getService$2("content-types");
|
2463
|
+
const metricsService = getService$2("metrics");
|
2179
2464
|
const contentType = await contentTypeService.findContentType(uid2);
|
2180
2465
|
if (!contentType) {
|
2181
2466
|
return ctx.notFound("contentType.notFound");
|
2182
2467
|
}
|
2183
|
-
if (!getService$
|
2468
|
+
if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
|
2184
2469
|
return ctx.forbidden();
|
2185
2470
|
}
|
2186
2471
|
let input;
|
@@ -2213,10 +2498,10 @@ const contentTypes = {
|
|
2213
2498
|
};
|
2214
2499
|
const init = {
|
2215
2500
|
getInitData(ctx) {
|
2216
|
-
const { toDto } = getService$
|
2217
|
-
const { findAllComponents } = getService$
|
2218
|
-
const { getAllFieldSizes } = getService$
|
2219
|
-
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");
|
2220
2505
|
ctx.body = {
|
2221
2506
|
data: {
|
2222
2507
|
fieldSizes: getAllFieldSizes(),
|
@@ -2252,36 +2537,41 @@ const addFiltersClause = (params, filtersClause) => {
|
|
2252
2537
|
params.filters.$and.push(filtersClause);
|
2253
2538
|
};
|
2254
2539
|
const sanitizeMainField = (model, mainField, userAbility) => {
|
2255
|
-
const permissionChecker2 = getService$
|
2540
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2256
2541
|
userAbility,
|
2257
2542
|
model: model.uid
|
2258
2543
|
});
|
2259
|
-
|
2544
|
+
const isMainFieldListable = isListable(model, mainField);
|
2545
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2546
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2260
2547
|
return "id";
|
2261
2548
|
}
|
2262
|
-
if (
|
2263
|
-
|
2264
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2265
|
-
userAbility,
|
2266
|
-
model: "plugin::users-permissions.user"
|
2267
|
-
});
|
2268
|
-
if (userPermissionChecker.can.read()) {
|
2269
|
-
return "name";
|
2270
|
-
}
|
2271
|
-
}
|
2272
|
-
return "id";
|
2549
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2550
|
+
return "name";
|
2273
2551
|
}
|
2274
2552
|
return mainField;
|
2275
2553
|
};
|
2276
|
-
const addStatusToRelations = async (
|
2277
|
-
if (!contentTypes$1.hasDraftAndPublish(strapi.
|
2554
|
+
const addStatusToRelations = async (targetUid, relations2) => {
|
2555
|
+
if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
2556
|
+
return relations2;
|
2557
|
+
}
|
2558
|
+
const documentMetadata2 = getService$2("document-metadata");
|
2559
|
+
if (!relations2.length) {
|
2278
2560
|
return relations2;
|
2279
2561
|
}
|
2280
|
-
const
|
2281
|
-
const
|
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
|
+
});
|
2282
2572
|
return relations2.map((relation) => {
|
2283
|
-
const availableStatuses =
|
2284
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2573
|
+
const availableStatuses = availableStatus.filter(
|
2574
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2285
2575
|
);
|
2286
2576
|
return {
|
2287
2577
|
...relation,
|
@@ -2302,11 +2592,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2302
2592
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2303
2593
|
const isSourceLocalized = isLocalized(sourceModel);
|
2304
2594
|
const isTargetLocalized = isLocalized(targetModel);
|
2305
|
-
let validatedLocale = locale;
|
2306
|
-
if (!targetModel || !isTargetLocalized)
|
2307
|
-
validatedLocale = void 0;
|
2308
2595
|
return {
|
2309
|
-
locale
|
2596
|
+
locale,
|
2310
2597
|
isSourceLocalized,
|
2311
2598
|
isTargetLocalized
|
2312
2599
|
};
|
@@ -2315,8 +2602,7 @@ const validateStatus = (sourceUid, status) => {
|
|
2315
2602
|
const sourceModel = strapi.getModel(sourceUid);
|
2316
2603
|
const isDP = contentTypes$1.hasDraftAndPublish;
|
2317
2604
|
const isSourceDP = isDP(sourceModel);
|
2318
|
-
if (!isSourceDP)
|
2319
|
-
return { status: void 0 };
|
2605
|
+
if (!isSourceDP) return { status: void 0 };
|
2320
2606
|
switch (status) {
|
2321
2607
|
case "published":
|
2322
2608
|
return { status: "published" };
|
@@ -2346,7 +2632,7 @@ const relations = {
|
|
2346
2632
|
ctx.request?.query?.locale
|
2347
2633
|
);
|
2348
2634
|
const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
|
2349
|
-
const permissionChecker2 = getService$
|
2635
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2350
2636
|
userAbility,
|
2351
2637
|
model
|
2352
2638
|
});
|
@@ -2371,7 +2657,7 @@ const relations = {
|
|
2371
2657
|
where.id = id;
|
2372
2658
|
}
|
2373
2659
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2374
|
-
const populate = await getService$
|
2660
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2375
2661
|
const currentEntity = await strapi.db.query(model).findOne({
|
2376
2662
|
where,
|
2377
2663
|
populate
|
@@ -2386,7 +2672,7 @@ const relations = {
|
|
2386
2672
|
}
|
2387
2673
|
entryId = currentEntity.id;
|
2388
2674
|
}
|
2389
|
-
const modelConfig = isComponent2 ? await getService$
|
2675
|
+
const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
|
2390
2676
|
const targetSchema = strapi.getModel(targetUid);
|
2391
2677
|
const mainField = flow(
|
2392
2678
|
prop(`metadatas.${targetField}.edit.mainField`),
|
@@ -2409,7 +2695,7 @@ const relations = {
|
|
2409
2695
|
attribute,
|
2410
2696
|
fieldsToSelect,
|
2411
2697
|
mainField,
|
2412
|
-
source: { schema: sourceSchema },
|
2698
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2413
2699
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2414
2700
|
sourceSchema,
|
2415
2701
|
targetSchema,
|
@@ -2431,7 +2717,8 @@ const relations = {
|
|
2431
2717
|
fieldsToSelect,
|
2432
2718
|
mainField,
|
2433
2719
|
source: {
|
2434
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2720
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2721
|
+
isLocalized: isSourceLocalized
|
2435
2722
|
},
|
2436
2723
|
target: {
|
2437
2724
|
schema: { uid: targetUid },
|
@@ -2439,7 +2726,7 @@ const relations = {
|
|
2439
2726
|
}
|
2440
2727
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2441
2728
|
const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
2442
|
-
const permissionChecker2 = getService$
|
2729
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2443
2730
|
userAbility: ctx.state.userAbility,
|
2444
2731
|
model: targetUid
|
2445
2732
|
});
|
@@ -2469,12 +2756,16 @@ const relations = {
|
|
2469
2756
|
} else {
|
2470
2757
|
where.id = id;
|
2471
2758
|
}
|
2472
|
-
|
2473
|
-
|
2759
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2760
|
+
if (!isEmpty(publishedAt)) {
|
2761
|
+
where[`${alias}.published_at`] = publishedAt;
|
2474
2762
|
}
|
2475
|
-
if (
|
2763
|
+
if (isTargetLocalized && locale) {
|
2476
2764
|
where[`${alias}.locale`] = locale;
|
2477
2765
|
}
|
2766
|
+
if (isSourceLocalized && locale) {
|
2767
|
+
where.locale = locale;
|
2768
|
+
}
|
2478
2769
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2479
2770
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2480
2771
|
}
|
@@ -2492,7 +2783,8 @@ const relations = {
|
|
2492
2783
|
id: { $notIn: uniq(idsToOmit) }
|
2493
2784
|
});
|
2494
2785
|
}
|
2495
|
-
const
|
2786
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2787
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2496
2788
|
ctx.body = {
|
2497
2789
|
...res,
|
2498
2790
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2507,29 +2799,39 @@ const relations = {
|
|
2507
2799
|
attribute,
|
2508
2800
|
targetField,
|
2509
2801
|
fieldsToSelect,
|
2510
|
-
|
2511
|
-
|
2512
|
-
}
|
2513
|
-
target: {
|
2514
|
-
schema: { uid: targetUid }
|
2515
|
-
}
|
2802
|
+
status,
|
2803
|
+
source: { schema: sourceSchema },
|
2804
|
+
target: { schema: targetSchema }
|
2516
2805
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2517
|
-
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 });
|
2518
2809
|
const dbQuery = strapi.db.query(sourceUid);
|
2519
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
|
+
}
|
2520
2823
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2521
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2824
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2522
2825
|
ordering: "desc",
|
2523
2826
|
page: ctx.request.query.page,
|
2524
|
-
pageSize: ctx.request.query.pageSize
|
2827
|
+
pageSize: ctx.request.query.pageSize,
|
2828
|
+
filters
|
2525
2829
|
});
|
2526
2830
|
const loadedIds = res.results.map((item) => item.id);
|
2527
2831
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2528
2832
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2529
2833
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2530
|
-
ordering: "desc"
|
2531
|
-
page: ctx.request.query.page,
|
2532
|
-
pageSize: ctx.request.query.pageSize
|
2834
|
+
ordering: "desc"
|
2533
2835
|
});
|
2534
2836
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2535
2837
|
ctx.body = {
|
@@ -2544,10 +2846,10 @@ const relations = {
|
|
2544
2846
|
}
|
2545
2847
|
};
|
2546
2848
|
const buildPopulateFromQuery = async (query, model) => {
|
2547
|
-
return getService$
|
2849
|
+
return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
|
2548
2850
|
};
|
2549
2851
|
const findDocument = async (query, uid2, opts = {}) => {
|
2550
|
-
const documentManager2 = getService$
|
2852
|
+
const documentManager2 = getService$2("document-manager");
|
2551
2853
|
const populate = await buildPopulateFromQuery(query, uid2);
|
2552
2854
|
return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
|
2553
2855
|
};
|
@@ -2555,13 +2857,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2555
2857
|
const { user, userAbility } = ctx.state;
|
2556
2858
|
const { model } = ctx.params;
|
2557
2859
|
const { body, query } = ctx.request;
|
2558
|
-
const documentManager2 = getService$
|
2559
|
-
const permissionChecker2 = getService$
|
2860
|
+
const documentManager2 = getService$2("document-manager");
|
2861
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2560
2862
|
if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
|
2561
2863
|
throw new errors.ForbiddenError();
|
2562
2864
|
}
|
2563
2865
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2564
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2866
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2565
2867
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2566
2868
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2567
2869
|
// Find the first document to check if it exists
|
@@ -2597,12 +2899,12 @@ const singleTypes = {
|
|
2597
2899
|
const { userAbility } = ctx.state;
|
2598
2900
|
const { model } = ctx.params;
|
2599
2901
|
const { query = {} } = ctx.request;
|
2600
|
-
const permissionChecker2 = getService$
|
2902
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2601
2903
|
if (permissionChecker2.cannot.read()) {
|
2602
2904
|
return ctx.forbidden();
|
2603
2905
|
}
|
2604
2906
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2605
|
-
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
2907
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2606
2908
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2607
2909
|
if (!version) {
|
2608
2910
|
if (permissionChecker2.cannot.create()) {
|
@@ -2616,7 +2918,7 @@ const singleTypes = {
|
|
2616
2918
|
permissionChecker2,
|
2617
2919
|
model,
|
2618
2920
|
// @ts-expect-error - fix types
|
2619
|
-
{
|
2921
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2620
2922
|
{ availableLocales: true, availableStatus: false }
|
2621
2923
|
);
|
2622
2924
|
ctx.body = { data: {}, meta };
|
@@ -2631,7 +2933,7 @@ const singleTypes = {
|
|
2631
2933
|
async createOrUpdate(ctx) {
|
2632
2934
|
const { userAbility } = ctx.state;
|
2633
2935
|
const { model } = ctx.params;
|
2634
|
-
const permissionChecker2 = getService$
|
2936
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2635
2937
|
const document = await createOrUpdateDocument(ctx);
|
2636
2938
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2637
2939
|
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
@@ -2640,14 +2942,14 @@ const singleTypes = {
|
|
2640
2942
|
const { userAbility } = ctx.state;
|
2641
2943
|
const { model } = ctx.params;
|
2642
2944
|
const { query = {} } = ctx.request;
|
2643
|
-
const documentManager2 = getService$
|
2644
|
-
const permissionChecker2 = getService$
|
2945
|
+
const documentManager2 = getService$2("document-manager");
|
2946
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2645
2947
|
if (permissionChecker2.cannot.delete()) {
|
2646
2948
|
return ctx.forbidden();
|
2647
2949
|
}
|
2648
2950
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2649
2951
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2650
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
2952
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2651
2953
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2652
2954
|
populate,
|
2653
2955
|
locale
|
@@ -2669,8 +2971,8 @@ const singleTypes = {
|
|
2669
2971
|
const { userAbility } = ctx.state;
|
2670
2972
|
const { model } = ctx.params;
|
2671
2973
|
const { query = {} } = ctx.request;
|
2672
|
-
const documentManager2 = getService$
|
2673
|
-
const permissionChecker2 = getService$
|
2974
|
+
const documentManager2 = getService$2("document-manager");
|
2975
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2674
2976
|
if (permissionChecker2.cannot.publish()) {
|
2675
2977
|
return ctx.forbidden();
|
2676
2978
|
}
|
@@ -2684,7 +2986,7 @@ const singleTypes = {
|
|
2684
2986
|
if (permissionChecker2.cannot.publish(document)) {
|
2685
2987
|
throw new errors.ForbiddenError();
|
2686
2988
|
}
|
2687
|
-
const { locale } = await getDocumentLocaleAndStatus(document);
|
2989
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2688
2990
|
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2689
2991
|
return publishResult.at(0);
|
2690
2992
|
});
|
@@ -2698,8 +3000,8 @@ const singleTypes = {
|
|
2698
3000
|
body: { discardDraft, ...body },
|
2699
3001
|
query = {}
|
2700
3002
|
} = ctx.request;
|
2701
|
-
const documentManager2 = getService$
|
2702
|
-
const permissionChecker2 = getService$
|
3003
|
+
const documentManager2 = getService$2("document-manager");
|
3004
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2703
3005
|
if (permissionChecker2.cannot.unpublish()) {
|
2704
3006
|
return ctx.forbidden();
|
2705
3007
|
}
|
@@ -2707,7 +3009,7 @@ const singleTypes = {
|
|
2707
3009
|
return ctx.forbidden();
|
2708
3010
|
}
|
2709
3011
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2710
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
3012
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2711
3013
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2712
3014
|
if (!document) {
|
2713
3015
|
return ctx.notFound();
|
@@ -2733,13 +3035,13 @@ const singleTypes = {
|
|
2733
3035
|
const { userAbility } = ctx.state;
|
2734
3036
|
const { model } = ctx.params;
|
2735
3037
|
const { body, query = {} } = ctx.request;
|
2736
|
-
const documentManager2 = getService$
|
2737
|
-
const permissionChecker2 = getService$
|
3038
|
+
const documentManager2 = getService$2("document-manager");
|
3039
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2738
3040
|
if (permissionChecker2.cannot.discard()) {
|
2739
3041
|
return ctx.forbidden();
|
2740
3042
|
}
|
2741
3043
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2742
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
3044
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2743
3045
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2744
3046
|
if (!document) {
|
2745
3047
|
return ctx.notFound();
|
@@ -2757,9 +3059,9 @@ const singleTypes = {
|
|
2757
3059
|
const { userAbility } = ctx.state;
|
2758
3060
|
const { model } = ctx.params;
|
2759
3061
|
const { query } = ctx.request;
|
2760
|
-
const documentManager2 = getService$
|
2761
|
-
const permissionChecker2 = getService$
|
2762
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
3062
|
+
const documentManager2 = getService$2("document-manager");
|
3063
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
3064
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2763
3065
|
if (permissionChecker2.cannot.read()) {
|
2764
3066
|
return ctx.forbidden();
|
2765
3067
|
}
|
@@ -2780,9 +3082,9 @@ const uid$1 = {
|
|
2780
3082
|
async generateUID(ctx) {
|
2781
3083
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2782
3084
|
const { query = {} } = ctx.request;
|
2783
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
3085
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2784
3086
|
await validateUIDField(contentTypeUID, field);
|
2785
|
-
const uidService = getService$
|
3087
|
+
const uidService = getService$2("uid");
|
2786
3088
|
ctx.body = {
|
2787
3089
|
data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
|
2788
3090
|
};
|
@@ -2792,9 +3094,9 @@ const uid$1 = {
|
|
2792
3094
|
ctx.request.body
|
2793
3095
|
);
|
2794
3096
|
const { query = {} } = ctx.request;
|
2795
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
3097
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2796
3098
|
await validateUIDField(contentTypeUID, field);
|
2797
|
-
const uidService = getService$
|
3099
|
+
const uidService = getService$2("uid");
|
2798
3100
|
const isAvailable = await uidService.checkUIDAvailability({
|
2799
3101
|
contentTypeUID,
|
2800
3102
|
field,
|
@@ -2815,7 +3117,8 @@ const controllers = {
|
|
2815
3117
|
relations,
|
2816
3118
|
"single-types": singleTypes,
|
2817
3119
|
uid: uid$1,
|
2818
|
-
...history.controllers ? history.controllers : {}
|
3120
|
+
...history.controllers ? history.controllers : {},
|
3121
|
+
...preview.controllers ? preview.controllers : {}
|
2819
3122
|
};
|
2820
3123
|
const keys = {
|
2821
3124
|
CONFIGURATION: "configuration"
|
@@ -2944,18 +3247,15 @@ async function syncMetadatas(configuration, schema) {
|
|
2944
3247
|
_.set(updatedMeta, ["list", "searchable"], false);
|
2945
3248
|
_.set(acc, [key], updatedMeta);
|
2946
3249
|
}
|
2947
|
-
if (!_.has(edit, "mainField"))
|
2948
|
-
return acc;
|
3250
|
+
if (!_.has(edit, "mainField")) return acc;
|
2949
3251
|
if (!isRelation$1(attr)) {
|
2950
3252
|
_.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
|
2951
3253
|
_.set(acc, [key], updatedMeta);
|
2952
3254
|
return acc;
|
2953
3255
|
}
|
2954
|
-
if (edit.mainField === "id")
|
2955
|
-
return acc;
|
3256
|
+
if (edit.mainField === "id") return acc;
|
2956
3257
|
const targetSchema = getTargetSchema(attr.targetModel);
|
2957
|
-
if (!targetSchema)
|
2958
|
-
return acc;
|
3258
|
+
if (!targetSchema) return acc;
|
2959
3259
|
if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
|
2960
3260
|
_.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
|
2961
3261
|
_.set(acc, [key], updatedMeta);
|
@@ -2966,12 +3266,12 @@ async function syncMetadatas(configuration, schema) {
|
|
2966
3266
|
return _.assign(metasWithDefaults, updatedMetas);
|
2967
3267
|
}
|
2968
3268
|
const getTargetSchema = (targetModel) => {
|
2969
|
-
return getService$
|
3269
|
+
return getService$2("content-types").findContentType(targetModel);
|
2970
3270
|
};
|
2971
3271
|
const DEFAULT_LIST_LENGTH = 4;
|
2972
3272
|
const MAX_ROW_SIZE = 12;
|
2973
3273
|
const isAllowedFieldSize = (type, size) => {
|
2974
|
-
const { getFieldSize } = getService$
|
3274
|
+
const { getFieldSize } = getService$2("field-sizes");
|
2975
3275
|
const fieldSize = getFieldSize(type);
|
2976
3276
|
if (!fieldSize.isResizable && size !== fieldSize.default) {
|
2977
3277
|
return false;
|
@@ -2979,7 +3279,7 @@ const isAllowedFieldSize = (type, size) => {
|
|
2979
3279
|
return size <= MAX_ROW_SIZE;
|
2980
3280
|
};
|
2981
3281
|
const getDefaultFieldSize = (attribute) => {
|
2982
|
-
const { hasFieldSize, getFieldSize } = getService$
|
3282
|
+
const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
|
2983
3283
|
return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
|
2984
3284
|
};
|
2985
3285
|
async function createDefaultLayouts(schema) {
|
@@ -3000,8 +3300,7 @@ function createDefaultEditLayout(schema) {
|
|
3000
3300
|
return appendToEditLayout([], keys2, schema);
|
3001
3301
|
}
|
3002
3302
|
function syncLayouts(configuration, schema) {
|
3003
|
-
if (_.isEmpty(configuration.layouts))
|
3004
|
-
return createDefaultLayouts(schema);
|
3303
|
+
if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
|
3005
3304
|
const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
|
3006
3305
|
let cleanList = list.filter((attr) => isListable(schema, attr));
|
3007
3306
|
const cleanEditRelations = editRelations.filter(
|
@@ -3012,9 +3311,8 @@ function syncLayouts(configuration, schema) {
|
|
3012
3311
|
for (const row of edit) {
|
3013
3312
|
const newRow = [];
|
3014
3313
|
for (const el of row) {
|
3015
|
-
if (!hasEditableAttribute(schema, el.name))
|
3016
|
-
|
3017
|
-
const { hasFieldSize } = getService$1("field-sizes");
|
3314
|
+
if (!hasEditableAttribute(schema, el.name)) continue;
|
3315
|
+
const { hasFieldSize } = getService$2("field-sizes");
|
3018
3316
|
const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
|
3019
3317
|
if (!isAllowedFieldSize(fieldType, el.size)) {
|
3020
3318
|
elementsToReAppend.push(el.name);
|
@@ -3044,8 +3342,7 @@ function syncLayouts(configuration, schema) {
|
|
3044
3342
|
};
|
3045
3343
|
}
|
3046
3344
|
const appendToEditLayout = (layout = [], keysToAppend, schema) => {
|
3047
|
-
if (keysToAppend.length === 0)
|
3048
|
-
return layout;
|
3345
|
+
if (keysToAppend.length === 0) return layout;
|
3049
3346
|
let currentRowIndex = Math.max(layout.length - 1, 0);
|
3050
3347
|
if (!layout[currentRowIndex]) {
|
3051
3348
|
layout[currentRowIndex] = [];
|
@@ -3154,17 +3451,17 @@ const configurationService$1 = createConfigurationService({
|
|
3154
3451
|
isComponent: true,
|
3155
3452
|
prefix: STORE_KEY_PREFIX,
|
3156
3453
|
getModels() {
|
3157
|
-
const { toContentManagerModel } = getService$
|
3454
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3158
3455
|
return mapValues(toContentManagerModel, strapi.components);
|
3159
3456
|
}
|
3160
3457
|
});
|
3161
3458
|
const components = ({ strapi: strapi2 }) => ({
|
3162
3459
|
findAllComponents() {
|
3163
|
-
const { toContentManagerModel } = getService$
|
3460
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3164
3461
|
return Object.values(strapi2.components).map(toContentManagerModel);
|
3165
3462
|
},
|
3166
3463
|
findComponent(uid2) {
|
3167
|
-
const { toContentManagerModel } = getService$
|
3464
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3168
3465
|
const component = strapi2.components[uid2];
|
3169
3466
|
return isNil$1(component) ? component : toContentManagerModel(component);
|
3170
3467
|
},
|
@@ -3215,17 +3512,17 @@ const configurationService = createConfigurationService({
|
|
3215
3512
|
storeUtils,
|
3216
3513
|
prefix: "content_types",
|
3217
3514
|
getModels() {
|
3218
|
-
const { toContentManagerModel } = getService$
|
3515
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3219
3516
|
return mapValues(toContentManagerModel, strapi.contentTypes);
|
3220
3517
|
}
|
3221
3518
|
});
|
3222
3519
|
const service = ({ strapi: strapi2 }) => ({
|
3223
3520
|
findAllContentTypes() {
|
3224
|
-
const { toContentManagerModel } = getService$
|
3521
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3225
3522
|
return Object.values(strapi2.contentTypes).map(toContentManagerModel);
|
3226
3523
|
},
|
3227
3524
|
findContentType(uid2) {
|
3228
|
-
const { toContentManagerModel } = getService$
|
3525
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3229
3526
|
const contentType = strapi2.contentTypes[uid2];
|
3230
3527
|
return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
|
3231
3528
|
},
|
@@ -3254,7 +3551,7 @@ const service = ({ strapi: strapi2 }) => ({
|
|
3254
3551
|
return this.findConfiguration(contentType);
|
3255
3552
|
},
|
3256
3553
|
findComponentsConfigurations(contentType) {
|
3257
|
-
return getService$
|
3554
|
+
return getService$2("components").findComponentsConfigurations(contentType);
|
3258
3555
|
},
|
3259
3556
|
syncConfigurations() {
|
3260
3557
|
return configurationService.syncConfigurations();
|
@@ -3435,12 +3732,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3435
3732
|
ability: userAbility,
|
3436
3733
|
model
|
3437
3734
|
});
|
3438
|
-
const
|
3735
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3736
|
+
const toSubject = (entity) => {
|
3737
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3738
|
+
};
|
3439
3739
|
const can = (action, entity, field) => {
|
3440
|
-
|
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
|
+
);
|
3441
3747
|
};
|
3442
3748
|
const cannot = (action, entity, field) => {
|
3443
|
-
|
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
|
+
);
|
3444
3756
|
};
|
3445
3757
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3446
3758
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3511,7 +3823,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3511
3823
|
return userAbility.can(action);
|
3512
3824
|
},
|
3513
3825
|
async registerPermissions() {
|
3514
|
-
const displayedContentTypes = getService$
|
3826
|
+
const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
|
3515
3827
|
const contentTypesUids = displayedContentTypes.map(prop("uid"));
|
3516
3828
|
const actions = [
|
3517
3829
|
{
|
@@ -3596,6 +3908,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
|
|
3596
3908
|
if (initialPopulate) {
|
3597
3909
|
return initialPopulate;
|
3598
3910
|
}
|
3911
|
+
if (attributeName === "localizations") {
|
3912
|
+
const validationPopulate = getPopulateForValidation(model.uid);
|
3913
|
+
return {
|
3914
|
+
populate: validationPopulate.populate
|
3915
|
+
};
|
3916
|
+
}
|
3599
3917
|
if (!isVisibleAttribute$1(model, attributeName)) {
|
3600
3918
|
return true;
|
3601
3919
|
}
|
@@ -3655,6 +3973,9 @@ const getDeepPopulate = (uid2, {
|
|
3655
3973
|
return {};
|
3656
3974
|
}
|
3657
3975
|
const model = strapi.getModel(uid2);
|
3976
|
+
if (!model) {
|
3977
|
+
return {};
|
3978
|
+
}
|
3658
3979
|
return Object.keys(model.attributes).reduce(
|
3659
3980
|
(populateAcc, attributeName) => merge(
|
3660
3981
|
populateAcc,
|
@@ -3674,40 +3995,46 @@ const getDeepPopulate = (uid2, {
|
|
3674
3995
|
{}
|
3675
3996
|
);
|
3676
3997
|
};
|
3677
|
-
const
|
3678
|
-
|
3679
|
-
|
3680
|
-
countOne = false,
|
3681
|
-
maxLevel = Infinity
|
3682
|
-
} = {}, level = 1) => {
|
3683
|
-
if (level > maxLevel) {
|
3998
|
+
const getPopulateForValidation = (uid2) => {
|
3999
|
+
const model = strapi.getModel(uid2);
|
4000
|
+
if (!model) {
|
3684
4001
|
return {};
|
3685
4002
|
}
|
3686
|
-
const model = strapi.getModel(uid2);
|
3687
4003
|
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3688
|
-
if (
|
4004
|
+
if (isScalarAttribute(attribute)) {
|
4005
|
+
if (getDoesAttributeRequireValidation(attribute)) {
|
4006
|
+
populateAcc.fields = populateAcc.fields || [];
|
4007
|
+
populateAcc.fields.push(attributeName);
|
4008
|
+
}
|
3689
4009
|
return populateAcc;
|
3690
4010
|
}
|
3691
|
-
if (
|
3692
|
-
|
3693
|
-
|
3694
|
-
|
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;
|
3695
4019
|
}
|
3696
|
-
|
3697
|
-
|
3698
|
-
|
3699
|
-
|
3700
|
-
|
3701
|
-
|
3702
|
-
|
3703
|
-
|
3704
|
-
|
3705
|
-
countOne,
|
3706
|
-
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;
|
3707
4029
|
},
|
3708
|
-
|
3709
|
-
)
|
3710
|
-
|
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;
|
3711
4038
|
}, {});
|
3712
4039
|
};
|
3713
4040
|
const getDeepPopulateDraftCount = (uid2) => {
|
@@ -3717,6 +4044,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3717
4044
|
const attribute = model.attributes[attributeName];
|
3718
4045
|
switch (attribute.type) {
|
3719
4046
|
case "relation": {
|
4047
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
4048
|
+
if (isMorphRelation) {
|
4049
|
+
break;
|
4050
|
+
}
|
3720
4051
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3721
4052
|
populateAcc[attributeName] = {
|
3722
4053
|
count: true,
|
@@ -3783,7 +4114,7 @@ const getQueryPopulate = async (uid2, query) => {
|
|
3783
4114
|
return populateQuery;
|
3784
4115
|
};
|
3785
4116
|
const buildDeepPopulate = (uid2) => {
|
3786
|
-
return getService$
|
4117
|
+
return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
|
3787
4118
|
};
|
3788
4119
|
const populateBuilder = (uid2) => {
|
3789
4120
|
let getInitialPopulate = async () => {
|
@@ -3945,7 +4276,6 @@ const AVAILABLE_LOCALES_FIELDS = [
|
|
3945
4276
|
"locale",
|
3946
4277
|
"updatedAt",
|
3947
4278
|
"createdAt",
|
3948
|
-
"status",
|
3949
4279
|
"publishedAt",
|
3950
4280
|
"documentId"
|
3951
4281
|
];
|
@@ -3966,34 +4296,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3966
4296
|
/**
|
3967
4297
|
* Returns available locales of a document for the current status
|
3968
4298
|
*/
|
3969
|
-
async getAvailableLocales(uid2, version, allVersions
|
4299
|
+
async getAvailableLocales(uid2, version, allVersions) {
|
3970
4300
|
const versionsByLocale = groupBy("locale", allVersions);
|
3971
|
-
|
4301
|
+
if (version.locale) {
|
4302
|
+
delete versionsByLocale[version.locale];
|
4303
|
+
}
|
3972
4304
|
const model = strapi2.getModel(uid2);
|
3973
|
-
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
3974
|
-
const traversalFunction = async (localeVersion) => traverseEntity(
|
3975
|
-
({ key }, { remove }) => {
|
3976
|
-
if (keysToKeep.includes(key)) {
|
3977
|
-
return;
|
3978
|
-
}
|
3979
|
-
remove(key);
|
3980
|
-
},
|
3981
|
-
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
3982
|
-
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
3983
|
-
localeVersion
|
3984
|
-
);
|
3985
4305
|
const mappingResult = await async.map(
|
3986
4306
|
Object.values(versionsByLocale),
|
3987
4307
|
async (localeVersions) => {
|
3988
|
-
const mappedLocaleVersions = await async.map(
|
3989
|
-
localeVersions,
|
3990
|
-
traversalFunction
|
3991
|
-
);
|
3992
4308
|
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
3993
|
-
return
|
4309
|
+
return localeVersions[0];
|
3994
4310
|
}
|
3995
|
-
const draftVersion =
|
3996
|
-
const otherVersions =
|
4311
|
+
const draftVersion = localeVersions.find((v) => v.publishedAt === null);
|
4312
|
+
const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
|
3997
4313
|
if (!draftVersion) {
|
3998
4314
|
return;
|
3999
4315
|
}
|
@@ -4015,8 +4331,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4015
4331
|
const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
|
4016
4332
|
return matchLocale && matchStatus;
|
4017
4333
|
});
|
4018
|
-
if (!availableStatus)
|
4019
|
-
return availableStatus;
|
4334
|
+
if (!availableStatus) return availableStatus;
|
4020
4335
|
return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
|
4021
4336
|
},
|
4022
4337
|
/**
|
@@ -4026,18 +4341,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4026
4341
|
* @returns
|
4027
4342
|
*/
|
4028
4343
|
async getManyAvailableStatus(uid2, documents) {
|
4029
|
-
if (!documents.length)
|
4030
|
-
return [];
|
4344
|
+
if (!documents.length) return [];
|
4031
4345
|
const status = documents[0].publishedAt !== null ? "published" : "draft";
|
4032
|
-
const
|
4033
|
-
const
|
4034
|
-
|
4035
|
-
|
4036
|
-
|
4037
|
-
|
4038
|
-
|
4039
|
-
|
4040
|
-
|
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"]
|
4041
4357
|
});
|
4042
4358
|
},
|
4043
4359
|
getStatus(version, otherDocumentStatuses) {
|
@@ -4054,10 +4370,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4054
4370
|
} else if (otherVersion) {
|
4055
4371
|
draftVersion = otherVersion;
|
4056
4372
|
}
|
4057
|
-
if (!draftVersion)
|
4058
|
-
|
4059
|
-
if (!publishedVersion)
|
4060
|
-
return CONTENT_MANAGER_STATUS.DRAFT;
|
4373
|
+
if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
|
4374
|
+
if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
|
4061
4375
|
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4062
4376
|
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
4063
4377
|
},
|
@@ -4065,11 +4379,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4065
4379
|
// We could refactor this so the locales are only loaded when they're
|
4066
4380
|
// needed. e.g. in the bulk locale action modal.
|
4067
4381
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4068
|
-
const populate =
|
4069
|
-
const
|
4070
|
-
where: { documentId: version.documentId },
|
4382
|
+
const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
|
4383
|
+
const params = {
|
4071
4384
|
populate: {
|
4072
|
-
// Populate only fields that require validation for bulk locale actions
|
4073
4385
|
...populate,
|
4074
4386
|
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
4075
4387
|
createdBy: {
|
@@ -4078,9 +4390,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4078
4390
|
updatedBy: {
|
4079
4391
|
select: ["id", "firstname", "lastname", "email"]
|
4080
4392
|
}
|
4393
|
+
},
|
4394
|
+
fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
|
4395
|
+
filters: {
|
4396
|
+
documentId: version.documentId
|
4081
4397
|
}
|
4082
|
-
}
|
4083
|
-
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) : [];
|
4084
4402
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
4085
4403
|
return {
|
4086
4404
|
availableLocales: availableLocalesResult,
|
@@ -4094,13 +4412,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4094
4412
|
*/
|
4095
4413
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
4096
4414
|
if (!document) {
|
4097
|
-
return
|
4415
|
+
return {
|
4416
|
+
data: document,
|
4417
|
+
meta: {
|
4418
|
+
availableLocales: [],
|
4419
|
+
availableStatus: []
|
4420
|
+
}
|
4421
|
+
};
|
4098
4422
|
}
|
4099
4423
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
4100
4424
|
if (!hasDraftAndPublish) {
|
4101
4425
|
opts.availableStatus = false;
|
4102
4426
|
}
|
4103
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
|
+
}
|
4104
4438
|
return {
|
4105
4439
|
data: {
|
4106
4440
|
...document,
|
@@ -4202,10 +4536,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4202
4536
|
async clone(id, body, uid2) {
|
4203
4537
|
const populate = await buildDeepPopulate(uid2);
|
4204
4538
|
const params = {
|
4205
|
-
data:
|
4206
|
-
...omitIdField(body),
|
4207
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4208
|
-
},
|
4539
|
+
data: omitIdField(body),
|
4209
4540
|
populate
|
4210
4541
|
};
|
4211
4542
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4321,7 +4652,8 @@ const services = {
|
|
4321
4652
|
permission,
|
4322
4653
|
"populate-builder": populateBuilder$1,
|
4323
4654
|
uid,
|
4324
|
-
...history.services ? history.services : {}
|
4655
|
+
...history.services ? history.services : {},
|
4656
|
+
...preview.services ? preview.services : {}
|
4325
4657
|
};
|
4326
4658
|
const index = () => {
|
4327
4659
|
return {
|