@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.19d775295eb622de3e659110caf22fcd2cd5d10d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
- package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
- package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs → ComponentConfigurationPage-B_99pmC0.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-B_99pmC0.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-NeMPjY5M.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-NeMPjY5M.js.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-CRbtQEUV.js} +9 -4
- package/dist/_chunks/ComponentIcon-CRbtQEUV.js.map +1 -0
- package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
- package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs → EditConfigurationPage-B0kNlNoj.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-B0kNlNoj.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-n7_xHayb.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-n7_xHayb.js.map} +1 -1
- package/dist/_chunks/EditViewPage-BT7Achc-.js +209 -0
- package/dist/_chunks/EditViewPage-BT7Achc-.js.map +1 -0
- package/dist/_chunks/EditViewPage-DYXZs4_2.mjs +191 -0
- package/dist/_chunks/EditViewPage-DYXZs4_2.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-CQ67ZifP.js → Form-BRmk2Dp3.js} +68 -49
- package/dist/_chunks/Form-BRmk2Dp3.js.map +1 -0
- package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-D3paRF1F.mjs} +67 -46
- package/dist/_chunks/Form-D3paRF1F.mjs.map +1 -0
- package/dist/_chunks/{History-BLEnudTX.js → History-BQpDoOu8.js} +211 -148
- package/dist/_chunks/History-BQpDoOu8.js.map +1 -0
- package/dist/_chunks/{History-DKhZAPcK.mjs → History-CzQbTOwa.mjs} +204 -139
- package/dist/_chunks/History-CzQbTOwa.mjs.map +1 -0
- package/dist/_chunks/{Field-kVFO4ZKB.mjs → Input-ww3KFYZr.mjs} +1996 -1730
- package/dist/_chunks/Input-ww3KFYZr.mjs.map +1 -0
- package/dist/_chunks/{Field-kq1c2TF1.js → Input-yM6HnyQa.js} +2035 -1770
- package/dist/_chunks/Input-yM6HnyQa.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-B6NsS-0m.js} +72 -63
- package/dist/_chunks/ListConfigurationPage-B6NsS-0m.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-Bbw8w5cS.mjs} +68 -57
- package/dist/_chunks/ListConfigurationPage-Bbw8w5cS.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-DnOP55pM.mjs} +179 -160
- package/dist/_chunks/ListViewPage-DnOP55pM.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-Dt8OUTwO.js} +183 -165
- package/dist/_chunks/ListViewPage-Dt8OUTwO.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-CXKXHNMa.mjs} +3 -3
- package/dist/_chunks/NoContentTypePage-CXKXHNMa.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-Dgm-uj-6.js} +3 -3
- package/dist/_chunks/NoContentTypePage-Dgm-uj-6.js.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-CLbU5SOt.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-CLbU5SOt.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-kaj1rPiW.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-kaj1rPiW.mjs.map} +1 -1
- package/dist/_chunks/Preview-Bieh13Ro.mjs +287 -0
- package/dist/_chunks/Preview-Bieh13Ro.mjs.map +1 -0
- package/dist/_chunks/Preview-CbXHXqBg.js +305 -0
- package/dist/_chunks/Preview-CbXHXqBg.js.map +1 -0
- package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-7rWJcZ3_.mjs} +138 -94
- package/dist/_chunks/Relations-7rWJcZ3_.mjs.map +1 -0
- package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-CvifV6Y6.js} +142 -100
- package/dist/_chunks/Relations-CvifV6Y6.js.map +1 -0
- package/dist/_chunks/{en-C-V1_90f.js → en-BR48D_RH.js} +45 -18
- package/dist/_chunks/{en-C-V1_90f.js.map → en-BR48D_RH.js.map} +1 -1
- package/dist/_chunks/{en-MBPul9Su.mjs → en-D65uIF6Y.mjs} +45 -18
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
- package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
- package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
- package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
- package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-CAc9yTnx.mjs → index-BH2JnYpF.mjs} +2302 -995
- package/dist/_chunks/index-BH2JnYpF.mjs.map +1 -0
- package/dist/_chunks/{index-DNa1J4HE.js → index-DkJQjlak.js} +2273 -967
- package/dist/_chunks/index-DkJQjlak.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-BqtLA6Lb.js → layout-4BqLFW_b.js} +47 -32
- package/dist/_chunks/layout-4BqLFW_b.js.map +1 -0
- package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-bbOlPwLA.mjs} +46 -28
- package/dist/_chunks/layout-bbOlPwLA.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-mMFEcZRq.mjs → relations-HsflnFpO.mjs} +6 -7
- package/dist/_chunks/relations-HsflnFpO.mjs.map +1 -0
- package/dist/_chunks/{relations-BHY_KDJ_.js → relations-Yc0Z6A20.js} +6 -7
- package/dist/_chunks/relations-Yc0Z6A20.js.map +1 -0
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
- package/dist/_chunks/useDragAndDrop-BMtgCYzL.js.map +1 -0
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
- package/dist/_chunks/useDragAndDrop-DJ6jqvZN.mjs.map +1 -0
- package/dist/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
- package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
- package/dist/_chunks/usePrev-D5J_2fEu.js +28 -0
- package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
- package/dist/admin/index.js +4 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +10 -7
- package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
- package/dist/admin/src/content-manager.d.ts +7 -5
- package/dist/admin/src/exports.d.ts +3 -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 +54 -9
- package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
- package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
- package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +12 -5
- 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/BlocksInput.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +5 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/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 +30 -18
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
- 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/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
- 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 +2 -3
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +5 -5
- package/dist/admin/src/services/documents.d.ts +31 -20
- package/dist/admin/src/services/init.d.ts +2 -2
- package/dist/admin/src/services/relations.d.ts +3 -3
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/api.d.ts +4 -18
- package/dist/admin/src/utils/validation.d.ts +5 -7
- package/dist/server/index.js +959 -543
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +960 -543
- 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/single-types.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +23 -0
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/index.d.ts +1 -1
- package/dist/server/src/history/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 +21 -36
- 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 +11 -6
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +16 -35
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +21 -36
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts +8 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/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 +17 -7
- 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/contracts/relations.d.ts +2 -2
- package/dist/shared/contracts/relations.d.ts.map +1 -1
- 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 +22 -22
- package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
- package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
- package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
- package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-KRG56aCq.js +0 -224
- package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
- package/dist/_chunks/EditViewPage-aUnqL-63.mjs +0 -203
- package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
- package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
- package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
- package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
- package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
- package/dist/_chunks/History-BLEnudTX.js.map +0 -1
- package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
- package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
- package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
- package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
- package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
- package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
- package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
- package/dist/_chunks/relations-BHY_KDJ_.js.map +0 -1
- package/dist/_chunks/relations-mMFEcZRq.mjs.map +0 -1
- package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
- package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
- package/dist/_chunks/urls-DzZya_gm.js +0 -6
- package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
- package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +0 -1
- package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +0 -1
- package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
- package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
- package/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, pagination
|
2
|
-
import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy
|
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
|
-
|
385
|
-
|
386
|
-
|
391
|
+
utils.set(options.key, {
|
392
|
+
results: sanitizedResults,
|
393
|
+
meta: response.meta
|
394
|
+
});
|
395
|
+
}
|
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
|
+
});
|
387
409
|
}
|
388
|
-
return currentDataWithRelations;
|
389
410
|
},
|
390
|
-
|
411
|
+
{
|
412
|
+
schema,
|
413
|
+
getModel: strapi2.getModel.bind(strapi2)
|
414
|
+
},
|
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
|
+
}
|
463
|
+
}
|
464
|
+
if (options.attribute.type === "dynamiczone") {
|
465
|
+
if (options.value === null) {
|
466
|
+
utils.set(options.key, []);
|
467
|
+
}
|
439
468
|
}
|
440
|
-
if (attribute.type === "relation" && // TODO: handle polymorphic relations
|
441
|
-
attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
|
442
|
-
|
443
|
-
|
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);
|
444
477
|
}
|
445
|
-
if (attribute.type === "media") {
|
446
|
-
|
447
|
-
|
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,65 +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 !== "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
|
-
|
554
|
+
if (!shouldCreateHistoryVersion(context)) {
|
555
|
+
return result;
|
556
|
+
}
|
557
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
493
558
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
494
|
-
const
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
559
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
560
|
+
if (!locales.length) {
|
561
|
+
return result;
|
562
|
+
}
|
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
|
+
)
|
499
578
|
});
|
500
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
501
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
502
|
-
const componentsSchemas = Object.keys(
|
503
|
-
attributesSchema
|
504
|
-
).reduce((currentComponentSchemas, key) => {
|
505
|
-
const fieldSchema = attributesSchema[key];
|
506
|
-
if (fieldSchema.type === "component") {
|
507
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
508
|
-
return {
|
509
|
-
...currentComponentSchemas,
|
510
|
-
[fieldSchema.component]: componentSchema
|
511
|
-
};
|
512
|
-
}
|
513
|
-
return currentComponentSchemas;
|
514
|
-
}, {});
|
515
579
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
516
|
-
onCommit(() => {
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
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
|
+
}
|
526
592
|
});
|
527
593
|
});
|
528
594
|
return result;
|
529
595
|
});
|
530
|
-
|
531
|
-
|
532
|
-
const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
|
596
|
+
state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
|
597
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
533
598
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
534
|
-
query.deleteMany({
|
599
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
535
600
|
where: {
|
536
601
|
created_at: {
|
537
|
-
$lt: expirationDate
|
602
|
+
$lt: expirationDate
|
538
603
|
}
|
539
604
|
}
|
605
|
+
}).catch((error) => {
|
606
|
+
if (error instanceof Error) {
|
607
|
+
strapi2.log.error("Error deleting expired history versions", error.message);
|
608
|
+
}
|
540
609
|
});
|
541
610
|
});
|
542
611
|
state.isInitialized = true;
|
@@ -548,17 +617,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
548
617
|
}
|
549
618
|
};
|
550
619
|
};
|
551
|
-
const services$
|
620
|
+
const services$2 = {
|
552
621
|
history: createHistoryService,
|
553
622
|
lifecycles: createLifecyclesService
|
554
623
|
};
|
555
|
-
const info = { pluginName: "content-manager", type: "admin" };
|
624
|
+
const info$1 = { pluginName: "content-manager", type: "admin" };
|
556
625
|
const historyVersionRouter = {
|
557
626
|
type: "admin",
|
558
627
|
routes: [
|
559
628
|
{
|
560
629
|
method: "GET",
|
561
|
-
info,
|
630
|
+
info: info$1,
|
562
631
|
path: "/history-versions",
|
563
632
|
handler: "history-version.findMany",
|
564
633
|
config: {
|
@@ -567,7 +636,7 @@ const historyVersionRouter = {
|
|
567
636
|
},
|
568
637
|
{
|
569
638
|
method: "PUT",
|
570
|
-
info,
|
639
|
+
info: info$1,
|
571
640
|
path: "/history-versions/:versionId/restore",
|
572
641
|
handler: "history-version.restoreVersion",
|
573
642
|
config: {
|
@@ -576,7 +645,7 @@ const historyVersionRouter = {
|
|
576
645
|
}
|
577
646
|
]
|
578
647
|
};
|
579
|
-
const routes$
|
648
|
+
const routes$2 = {
|
580
649
|
"history-version": historyVersionRouter
|
581
650
|
};
|
582
651
|
const historyVersion = {
|
@@ -623,21 +692,21 @@ const historyVersion = {
|
|
623
692
|
}
|
624
693
|
}
|
625
694
|
};
|
626
|
-
const getFeature = () => {
|
695
|
+
const getFeature$1 = () => {
|
627
696
|
if (strapi.ee.features.isEnabled("cms-content-history")) {
|
628
697
|
return {
|
629
698
|
register({ strapi: strapi2 }) {
|
630
699
|
strapi2.get("models").add(historyVersion);
|
631
700
|
},
|
632
701
|
bootstrap({ strapi: strapi2 }) {
|
633
|
-
getService(strapi2, "lifecycles").bootstrap();
|
702
|
+
getService$1(strapi2, "lifecycles").bootstrap();
|
634
703
|
},
|
635
704
|
destroy({ strapi: strapi2 }) {
|
636
|
-
getService(strapi2, "lifecycles").destroy();
|
705
|
+
getService$1(strapi2, "lifecycles").destroy();
|
637
706
|
},
|
638
|
-
controllers: controllers$
|
639
|
-
services: services$
|
640
|
-
routes: routes$
|
707
|
+
controllers: controllers$2,
|
708
|
+
services: services$2,
|
709
|
+
routes: routes$2
|
641
710
|
};
|
642
711
|
}
|
643
712
|
return {
|
@@ -646,9 +715,201 @@ const getFeature = () => {
|
|
646
715
|
}
|
647
716
|
};
|
648
717
|
};
|
649
|
-
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();
|
650
910
|
const register = async ({ strapi: strapi2 }) => {
|
651
911
|
await history.register?.({ strapi: strapi2 });
|
912
|
+
await preview.register?.({ strapi: strapi2 });
|
652
913
|
};
|
653
914
|
const ALLOWED_WEBHOOK_EVENTS = {
|
654
915
|
ENTRY_PUBLISH: "entry.publish",
|
@@ -658,11 +919,12 @@ const bootstrap = async () => {
|
|
658
919
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
659
920
|
strapi.get("webhookStore").addAllowedEvent(key, value);
|
660
921
|
});
|
661
|
-
getService$
|
662
|
-
await getService$
|
663
|
-
await getService$
|
664
|
-
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();
|
665
926
|
await history.bootstrap?.({ strapi });
|
927
|
+
await preview.bootstrap?.({ strapi });
|
666
928
|
};
|
667
929
|
const destroy = async ({ strapi: strapi2 }) => {
|
668
930
|
await history.destroy?.({ strapi: strapi2 });
|
@@ -1152,7 +1414,8 @@ const admin = {
|
|
1152
1414
|
};
|
1153
1415
|
const routes = {
|
1154
1416
|
admin,
|
1155
|
-
...history.routes ? history.routes : {}
|
1417
|
+
...history.routes ? history.routes : {},
|
1418
|
+
...preview.routes ? preview.routes : {}
|
1156
1419
|
};
|
1157
1420
|
const hasPermissionsSchema = yup$1.object({
|
1158
1421
|
actions: yup$1.array().of(yup$1.string()),
|
@@ -1163,6 +1426,11 @@ const { createPolicy } = policy;
|
|
1163
1426
|
const hasPermissions = createPolicy({
|
1164
1427
|
name: "plugin::content-manager.hasPermissions",
|
1165
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
|
+
*/
|
1166
1434
|
handler(ctx, config = {}) {
|
1167
1435
|
const { actions = [], hasAtLeastOne = false } = config;
|
1168
1436
|
const { userAbility } = ctx.state;
|
@@ -1210,8 +1478,7 @@ const isSortable = (schema, name) => {
|
|
1210
1478
|
if (!_.has(schema.attributes, name)) {
|
1211
1479
|
return false;
|
1212
1480
|
}
|
1213
|
-
if (schema.modelType === "component" && name === "id")
|
1214
|
-
return false;
|
1481
|
+
if (schema.modelType === "component" && name === "id") return false;
|
1215
1482
|
const attribute = schema.attributes[name];
|
1216
1483
|
if (NON_SORTABLES.includes(attribute.type)) {
|
1217
1484
|
return false;
|
@@ -1356,8 +1623,7 @@ const createDefaultSettings = async (schema) => {
|
|
1356
1623
|
};
|
1357
1624
|
};
|
1358
1625
|
const syncSettings = async (configuration, schema) => {
|
1359
|
-
if (isEmpty(configuration.settings))
|
1360
|
-
return createDefaultSettings(schema);
|
1626
|
+
if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
|
1361
1627
|
const defaultField = getDefaultMainField(schema);
|
1362
1628
|
const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
|
1363
1629
|
return {
|
@@ -1404,7 +1670,7 @@ const createMetadasSchema = (schema) => {
|
|
1404
1670
|
if (!value) {
|
1405
1671
|
return yup$1.string();
|
1406
1672
|
}
|
1407
|
-
const targetSchema = getService$
|
1673
|
+
const targetSchema = getService$2("content-types").findContentType(
|
1408
1674
|
schema.attributes[key].targetModel
|
1409
1675
|
);
|
1410
1676
|
if (!targetSchema) {
|
@@ -1452,7 +1718,7 @@ const { PaginationError, ValidationError } = errors;
|
|
1452
1718
|
const TYPES = ["singleType", "collectionType"];
|
1453
1719
|
const kindSchema = yup$1.string().oneOf(TYPES).nullable();
|
1454
1720
|
const bulkActionInputSchema = yup$1.object({
|
1455
|
-
|
1721
|
+
documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
|
1456
1722
|
}).required();
|
1457
1723
|
const generateUIDInputSchema = yup$1.object({
|
1458
1724
|
contentTypeUID: yup$1.string().required(),
|
@@ -1533,8 +1799,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1533
1799
|
}
|
1534
1800
|
switch (attribute.type) {
|
1535
1801
|
case "relation": {
|
1536
|
-
if (canCreate(attributePath))
|
1537
|
-
return body2;
|
1802
|
+
if (canCreate(attributePath)) return body2;
|
1538
1803
|
return set(attributePath, { set: [] }, body2);
|
1539
1804
|
}
|
1540
1805
|
case "component": {
|
@@ -1544,29 +1809,62 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1544
1809
|
]);
|
1545
1810
|
}
|
1546
1811
|
default: {
|
1547
|
-
if (canCreate(attributePath))
|
1548
|
-
return body2;
|
1812
|
+
if (canCreate(attributePath)) return body2;
|
1549
1813
|
return set(attributePath, null, body2);
|
1550
1814
|
}
|
1551
1815
|
}
|
1552
1816
|
}, body);
|
1553
1817
|
};
|
1554
|
-
const
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1818
|
+
const singleLocaleSchema = yup$1.string().nullable();
|
1819
|
+
const multipleLocaleSchema = yup$1.lazy(
|
1820
|
+
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1821
|
+
);
|
1822
|
+
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1823
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1824
|
+
const { allowMultipleLocales } = opts;
|
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;
|
1828
|
+
const schema = yup$1.object().shape({
|
1829
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1830
|
+
status: statusSchema
|
1831
|
+
});
|
1832
|
+
try {
|
1833
|
+
await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1834
|
+
return { locale, status, ...rest };
|
1835
|
+
} catch (error) {
|
1836
|
+
throw new errors.ValidationError(`Validation error: ${error.message}`);
|
1561
1837
|
}
|
1562
|
-
|
1838
|
+
};
|
1839
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1840
|
+
const documentMetadata2 = getService$2("document-metadata");
|
1841
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1842
|
+
let {
|
1843
|
+
meta: { availableLocales, availableStatus }
|
1844
|
+
} = serviceOutput;
|
1845
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1846
|
+
availableLocales = await async.map(
|
1847
|
+
availableLocales,
|
1848
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1849
|
+
);
|
1850
|
+
availableStatus = await async.map(
|
1851
|
+
availableStatus,
|
1852
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1853
|
+
);
|
1854
|
+
return {
|
1855
|
+
...serviceOutput,
|
1856
|
+
meta: {
|
1857
|
+
availableLocales,
|
1858
|
+
availableStatus
|
1859
|
+
}
|
1860
|
+
};
|
1563
1861
|
};
|
1564
1862
|
const createDocument = async (ctx, opts) => {
|
1565
1863
|
const { userAbility, user } = ctx.state;
|
1566
1864
|
const { model } = ctx.params;
|
1567
1865
|
const { body } = ctx.request;
|
1568
|
-
const documentManager2 = getService$
|
1569
|
-
const permissionChecker2 = getService$
|
1866
|
+
const documentManager2 = getService$2("document-manager");
|
1867
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1570
1868
|
if (permissionChecker2.cannot.create()) {
|
1571
1869
|
throw new errors.ForbiddenError();
|
1572
1870
|
}
|
@@ -1574,7 +1872,7 @@ const createDocument = async (ctx, opts) => {
|
|
1574
1872
|
const setCreator = setCreatorFields({ user });
|
1575
1873
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1576
1874
|
const sanitizedBody = await sanitizeFn(body);
|
1577
|
-
const { locale, status
|
1875
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1578
1876
|
return documentManager2.create(model, {
|
1579
1877
|
data: sanitizedBody,
|
1580
1878
|
locale,
|
@@ -1586,14 +1884,14 @@ const updateDocument = async (ctx, opts) => {
|
|
1586
1884
|
const { userAbility, user } = ctx.state;
|
1587
1885
|
const { id, model } = ctx.params;
|
1588
1886
|
const { body } = ctx.request;
|
1589
|
-
const documentManager2 = getService$
|
1590
|
-
const permissionChecker2 = getService$
|
1887
|
+
const documentManager2 = getService$2("document-manager");
|
1888
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1591
1889
|
if (permissionChecker2.cannot.update()) {
|
1592
1890
|
throw new errors.ForbiddenError();
|
1593
1891
|
}
|
1594
1892
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1595
|
-
const populate = await getService$
|
1596
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1893
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1894
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1597
1895
|
const [documentVersion, documentExists] = await Promise.all([
|
1598
1896
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1599
1897
|
documentManager2.exists(model, id)
|
@@ -1609,7 +1907,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1609
1907
|
throw new errors.ForbiddenError();
|
1610
1908
|
}
|
1611
1909
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1612
|
-
const setCreator = setCreatorFields({ user, isEdition: true });
|
1910
|
+
const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
|
1613
1911
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1614
1912
|
const sanitizedBody = await sanitizeFn(body);
|
1615
1913
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1623,15 +1921,15 @@ const collectionTypes = {
|
|
1623
1921
|
const { userAbility } = ctx.state;
|
1624
1922
|
const { model } = ctx.params;
|
1625
1923
|
const { query } = ctx.request;
|
1626
|
-
const documentMetadata2 = getService$
|
1627
|
-
const documentManager2 = getService$
|
1628
|
-
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 });
|
1629
1927
|
if (permissionChecker2.cannot.read()) {
|
1630
1928
|
return ctx.forbidden();
|
1631
1929
|
}
|
1632
1930
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1633
|
-
const populate = await getService$
|
1634
|
-
const { locale, status } = 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);
|
1635
1933
|
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1636
1934
|
{ ...permissionQuery, populate, locale, status },
|
1637
1935
|
model
|
@@ -1659,15 +1957,14 @@ const collectionTypes = {
|
|
1659
1957
|
async findOne(ctx) {
|
1660
1958
|
const { userAbility } = ctx.state;
|
1661
1959
|
const { model, id } = ctx.params;
|
1662
|
-
const documentManager2 = getService$
|
1663
|
-
const
|
1664
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1960
|
+
const documentManager2 = getService$2("document-manager");
|
1961
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1665
1962
|
if (permissionChecker2.cannot.read()) {
|
1666
1963
|
return ctx.forbidden();
|
1667
1964
|
}
|
1668
1965
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1669
|
-
const populate = await getService$
|
1670
|
-
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);
|
1671
1968
|
const version = await documentManager2.findOne(id, model, {
|
1672
1969
|
populate,
|
1673
1970
|
locale,
|
@@ -1678,9 +1975,11 @@ const collectionTypes = {
|
|
1678
1975
|
if (!exists) {
|
1679
1976
|
return ctx.notFound();
|
1680
1977
|
}
|
1681
|
-
const { meta } = await
|
1978
|
+
const { meta } = await formatDocumentWithMetadata(
|
1979
|
+
permissionChecker2,
|
1682
1980
|
model,
|
1683
|
-
|
1981
|
+
// @ts-expect-error TODO: fix
|
1982
|
+
{ documentId: id, locale, publishedAt: null },
|
1684
1983
|
{ availableLocales: true, availableStatus: false }
|
1685
1984
|
);
|
1686
1985
|
ctx.body = { data: {}, meta };
|
@@ -1690,20 +1989,19 @@ const collectionTypes = {
|
|
1690
1989
|
return ctx.forbidden();
|
1691
1990
|
}
|
1692
1991
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1693
|
-
ctx.body = await
|
1992
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1694
1993
|
},
|
1695
1994
|
async create(ctx) {
|
1696
1995
|
const { userAbility } = ctx.state;
|
1697
1996
|
const { model } = ctx.params;
|
1698
|
-
const
|
1699
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1997
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1700
1998
|
const [totalEntries, document] = await Promise.all([
|
1701
1999
|
strapi.db.query(model).count(),
|
1702
2000
|
createDocument(ctx)
|
1703
2001
|
]);
|
1704
2002
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1705
2003
|
ctx.status = 201;
|
1706
|
-
ctx.body = await
|
2004
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1707
2005
|
// Empty metadata as it's not relevant for a new document
|
1708
2006
|
availableLocales: false,
|
1709
2007
|
availableStatus: false
|
@@ -1717,25 +2015,23 @@ const collectionTypes = {
|
|
1717
2015
|
async update(ctx) {
|
1718
2016
|
const { userAbility } = ctx.state;
|
1719
2017
|
const { model } = ctx.params;
|
1720
|
-
const
|
1721
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2018
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1722
2019
|
const updatedVersion = await updateDocument(ctx);
|
1723
2020
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1724
|
-
ctx.body = await
|
2021
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1725
2022
|
},
|
1726
2023
|
async clone(ctx) {
|
1727
2024
|
const { userAbility, user } = ctx.state;
|
1728
2025
|
const { model, sourceId: id } = ctx.params;
|
1729
2026
|
const { body } = ctx.request;
|
1730
|
-
const documentManager2 = getService$
|
1731
|
-
const
|
1732
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2027
|
+
const documentManager2 = getService$2("document-manager");
|
2028
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1733
2029
|
if (permissionChecker2.cannot.create()) {
|
1734
2030
|
return ctx.forbidden();
|
1735
2031
|
}
|
1736
2032
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1737
|
-
const populate = await getService$
|
1738
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2033
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2034
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1739
2035
|
const document = await documentManager2.findOne(id, model, {
|
1740
2036
|
populate,
|
1741
2037
|
locale,
|
@@ -1751,7 +2047,7 @@ const collectionTypes = {
|
|
1751
2047
|
const sanitizedBody = await sanitizeFn(body);
|
1752
2048
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1753
2049
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1754
|
-
ctx.body = await
|
2050
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1755
2051
|
// Empty metadata as it's not relevant for a new document
|
1756
2052
|
availableLocales: false,
|
1757
2053
|
availableStatus: false
|
@@ -1773,14 +2069,14 @@ const collectionTypes = {
|
|
1773
2069
|
async delete(ctx) {
|
1774
2070
|
const { userAbility } = ctx.state;
|
1775
2071
|
const { id, model } = ctx.params;
|
1776
|
-
const documentManager2 = getService$
|
1777
|
-
const permissionChecker2 = getService$
|
2072
|
+
const documentManager2 = getService$2("document-manager");
|
2073
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1778
2074
|
if (permissionChecker2.cannot.delete()) {
|
1779
2075
|
return ctx.forbidden();
|
1780
2076
|
}
|
1781
2077
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1782
|
-
const populate = await getService$
|
1783
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
2078
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2079
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1784
2080
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1785
2081
|
if (documentLocales.length === 0) {
|
1786
2082
|
return ctx.notFound();
|
@@ -1801,44 +2097,75 @@ const collectionTypes = {
|
|
1801
2097
|
const { userAbility } = ctx.state;
|
1802
2098
|
const { id, model } = ctx.params;
|
1803
2099
|
const { body } = ctx.request;
|
1804
|
-
const documentManager2 = getService$
|
1805
|
-
const
|
1806
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2100
|
+
const documentManager2 = getService$2("document-manager");
|
2101
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1807
2102
|
if (permissionChecker2.cannot.publish()) {
|
1808
2103
|
return ctx.forbidden();
|
1809
2104
|
}
|
1810
2105
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1811
2106
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1812
|
-
const populate = await getService$
|
1813
|
-
|
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
|
+
}
|
1814
2133
|
if (permissionChecker2.cannot.publish(document)) {
|
1815
2134
|
throw new errors.ForbiddenError();
|
1816
2135
|
}
|
1817
|
-
const
|
1818
|
-
return documentManager2.publish(document.documentId, model, {
|
2136
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1819
2137
|
locale
|
1820
2138
|
// TODO: Allow setting creator fields on publish
|
1821
2139
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1822
2140
|
});
|
2141
|
+
if (!publishResult || publishResult.length === 0) {
|
2142
|
+
throw new errors.NotFoundError("Document not found or already published.");
|
2143
|
+
}
|
2144
|
+
return publishResult[0];
|
1823
2145
|
});
|
1824
2146
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1825
|
-
ctx.body = await
|
2147
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1826
2148
|
},
|
1827
2149
|
async bulkPublish(ctx) {
|
1828
2150
|
const { userAbility } = ctx.state;
|
1829
2151
|
const { model } = ctx.params;
|
1830
2152
|
const { body } = ctx.request;
|
1831
|
-
const {
|
2153
|
+
const { documentIds } = body;
|
1832
2154
|
await validateBulkActionInput(body);
|
1833
|
-
const documentManager2 = getService$
|
1834
|
-
const permissionChecker2 = getService$
|
2155
|
+
const documentManager2 = getService$2("document-manager");
|
2156
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1835
2157
|
if (permissionChecker2.cannot.publish()) {
|
1836
2158
|
return ctx.forbidden();
|
1837
2159
|
}
|
1838
2160
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1839
|
-
const populate = await getService$
|
1840
|
-
const
|
1841
|
-
|
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
|
+
});
|
2165
|
+
const entityPromises = documentIds.map(
|
2166
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
2167
|
+
);
|
2168
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1842
2169
|
for (const entity of entities) {
|
1843
2170
|
if (!entity) {
|
1844
2171
|
return ctx.notFound();
|
@@ -1847,24 +2174,27 @@ const collectionTypes = {
|
|
1847
2174
|
return ctx.forbidden();
|
1848
2175
|
}
|
1849
2176
|
}
|
1850
|
-
const
|
2177
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1851
2178
|
ctx.body = { count };
|
1852
2179
|
},
|
1853
2180
|
async bulkUnpublish(ctx) {
|
1854
2181
|
const { userAbility } = ctx.state;
|
1855
2182
|
const { model } = ctx.params;
|
1856
2183
|
const { body } = ctx.request;
|
1857
|
-
const {
|
2184
|
+
const { documentIds } = body;
|
1858
2185
|
await validateBulkActionInput(body);
|
1859
|
-
const documentManager2 = getService$
|
1860
|
-
const permissionChecker2 = getService$
|
2186
|
+
const documentManager2 = getService$2("document-manager");
|
2187
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1861
2188
|
if (permissionChecker2.cannot.unpublish()) {
|
1862
2189
|
return ctx.forbidden();
|
1863
2190
|
}
|
1864
|
-
const
|
1865
|
-
|
1866
|
-
|
1867
|
-
const
|
2191
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2192
|
+
allowMultipleLocales: true
|
2193
|
+
});
|
2194
|
+
const entityPromises = documentIds.map(
|
2195
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
2196
|
+
);
|
2197
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1868
2198
|
for (const entity of entities) {
|
1869
2199
|
if (!entity) {
|
1870
2200
|
return ctx.notFound();
|
@@ -1873,7 +2203,8 @@ const collectionTypes = {
|
|
1873
2203
|
return ctx.forbidden();
|
1874
2204
|
}
|
1875
2205
|
}
|
1876
|
-
const
|
2206
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
2207
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1877
2208
|
ctx.body = { count };
|
1878
2209
|
},
|
1879
2210
|
async unpublish(ctx) {
|
@@ -1882,9 +2213,8 @@ const collectionTypes = {
|
|
1882
2213
|
const {
|
1883
2214
|
body: { discardDraft, ...body }
|
1884
2215
|
} = ctx.request;
|
1885
|
-
const documentManager2 = getService$
|
1886
|
-
const
|
1887
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2216
|
+
const documentManager2 = getService$2("document-manager");
|
2217
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1888
2218
|
if (permissionChecker2.cannot.unpublish()) {
|
1889
2219
|
return ctx.forbidden();
|
1890
2220
|
}
|
@@ -1892,8 +2222,8 @@ const collectionTypes = {
|
|
1892
2222
|
return ctx.forbidden();
|
1893
2223
|
}
|
1894
2224
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1895
|
-
const populate = await getService$
|
1896
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2225
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2226
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1897
2227
|
const document = await documentManager2.findOne(id, model, {
|
1898
2228
|
populate,
|
1899
2229
|
locale,
|
@@ -1915,7 +2245,7 @@ const collectionTypes = {
|
|
1915
2245
|
ctx.body = await async.pipe(
|
1916
2246
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1917
2247
|
permissionChecker2.sanitizeOutput,
|
1918
|
-
(document2) =>
|
2248
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1919
2249
|
)(document);
|
1920
2250
|
});
|
1921
2251
|
},
|
@@ -1923,15 +2253,14 @@ const collectionTypes = {
|
|
1923
2253
|
const { userAbility } = ctx.state;
|
1924
2254
|
const { id, model } = ctx.params;
|
1925
2255
|
const { body } = ctx.request;
|
1926
|
-
const documentManager2 = getService$
|
1927
|
-
const
|
1928
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2256
|
+
const documentManager2 = getService$2("document-manager");
|
2257
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1929
2258
|
if (permissionChecker2.cannot.discard()) {
|
1930
2259
|
return ctx.forbidden();
|
1931
2260
|
}
|
1932
2261
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1933
|
-
const populate = await getService$
|
1934
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2262
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2263
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1935
2264
|
const document = await documentManager2.findOne(id, model, {
|
1936
2265
|
populate,
|
1937
2266
|
locale,
|
@@ -1946,42 +2275,50 @@ const collectionTypes = {
|
|
1946
2275
|
ctx.body = await async.pipe(
|
1947
2276
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1948
2277
|
permissionChecker2.sanitizeOutput,
|
1949
|
-
(document2) =>
|
2278
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1950
2279
|
)(document);
|
1951
2280
|
},
|
1952
2281
|
async bulkDelete(ctx) {
|
1953
2282
|
const { userAbility } = ctx.state;
|
1954
2283
|
const { model } = ctx.params;
|
1955
2284
|
const { query, body } = ctx.request;
|
1956
|
-
const {
|
2285
|
+
const { documentIds } = body;
|
1957
2286
|
await validateBulkActionInput(body);
|
1958
|
-
const documentManager2 = getService$
|
1959
|
-
const permissionChecker2 = getService$
|
2287
|
+
const documentManager2 = getService$2("document-manager");
|
2288
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1960
2289
|
if (permissionChecker2.cannot.delete()) {
|
1961
2290
|
return ctx.forbidden();
|
1962
2291
|
}
|
1963
2292
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1964
|
-
const
|
1965
|
-
const
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
2293
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2294
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2295
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2296
|
+
populate,
|
2297
|
+
locale
|
2298
|
+
});
|
2299
|
+
if (documentLocales.length === 0) {
|
2300
|
+
return ctx.notFound();
|
2301
|
+
}
|
2302
|
+
for (const document of documentLocales) {
|
2303
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2304
|
+
return ctx.forbidden();
|
1969
2305
|
}
|
1970
|
-
}
|
1971
|
-
const
|
2306
|
+
}
|
2307
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2308
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1972
2309
|
ctx.body = { count };
|
1973
2310
|
},
|
1974
2311
|
async countDraftRelations(ctx) {
|
1975
2312
|
const { userAbility } = ctx.state;
|
1976
2313
|
const { model, id } = ctx.params;
|
1977
|
-
const documentManager2 = getService$
|
1978
|
-
const permissionChecker2 = getService$
|
2314
|
+
const documentManager2 = getService$2("document-manager");
|
2315
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1979
2316
|
if (permissionChecker2.cannot.read()) {
|
1980
2317
|
return ctx.forbidden();
|
1981
2318
|
}
|
1982
2319
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1983
|
-
const populate = await getService$
|
1984
|
-
const { locale, status
|
2320
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2321
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1985
2322
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
1986
2323
|
if (!entity) {
|
1987
2324
|
return ctx.notFound();
|
@@ -1996,24 +2333,24 @@ const collectionTypes = {
|
|
1996
2333
|
},
|
1997
2334
|
async countManyEntriesDraftRelations(ctx) {
|
1998
2335
|
const { userAbility } = ctx.state;
|
1999
|
-
const ids = ctx.request.query.
|
2336
|
+
const ids = ctx.request.query.documentIds;
|
2000
2337
|
const locale = ctx.request.query.locale;
|
2001
2338
|
const { model } = ctx.params;
|
2002
|
-
const documentManager2 = getService$
|
2003
|
-
const permissionChecker2 = getService$
|
2339
|
+
const documentManager2 = getService$2("document-manager");
|
2340
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2004
2341
|
if (permissionChecker2.cannot.read()) {
|
2005
2342
|
return ctx.forbidden();
|
2006
2343
|
}
|
2007
|
-
const
|
2344
|
+
const documents = await documentManager2.findMany(
|
2008
2345
|
{
|
2009
2346
|
filters: {
|
2010
|
-
|
2347
|
+
documentId: ids
|
2011
2348
|
},
|
2012
2349
|
locale
|
2013
2350
|
},
|
2014
2351
|
model
|
2015
2352
|
);
|
2016
|
-
if (!
|
2353
|
+
if (!documents) {
|
2017
2354
|
return ctx.notFound();
|
2018
2355
|
}
|
2019
2356
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2024,13 +2361,13 @@ const collectionTypes = {
|
|
2024
2361
|
};
|
2025
2362
|
const components$1 = {
|
2026
2363
|
findComponents(ctx) {
|
2027
|
-
const components2 = getService$
|
2028
|
-
const { toDto } = getService$
|
2364
|
+
const components2 = getService$2("components").findAllComponents();
|
2365
|
+
const { toDto } = getService$2("data-mapper");
|
2029
2366
|
ctx.body = { data: components2.map(toDto) };
|
2030
2367
|
},
|
2031
2368
|
async findComponentConfiguration(ctx) {
|
2032
2369
|
const { uid: uid2 } = ctx.params;
|
2033
|
-
const componentService = getService$
|
2370
|
+
const componentService = getService$2("components");
|
2034
2371
|
const component = componentService.findComponent(uid2);
|
2035
2372
|
if (!component) {
|
2036
2373
|
return ctx.notFound("component.notFound");
|
@@ -2047,7 +2384,7 @@ const components$1 = {
|
|
2047
2384
|
async updateComponentConfiguration(ctx) {
|
2048
2385
|
const { uid: uid2 } = ctx.params;
|
2049
2386
|
const { body } = ctx.request;
|
2050
|
-
const componentService = getService$
|
2387
|
+
const componentService = getService$2("components");
|
2051
2388
|
const component = componentService.findComponent(uid2);
|
2052
2389
|
if (!component) {
|
2053
2390
|
return ctx.notFound("component.notFound");
|
@@ -2081,12 +2418,12 @@ const contentTypes = {
|
|
2081
2418
|
} catch (error) {
|
2082
2419
|
return ctx.send({ error }, 400);
|
2083
2420
|
}
|
2084
|
-
const contentTypes2 = getService$
|
2085
|
-
const { toDto } = getService$
|
2421
|
+
const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
|
2422
|
+
const { toDto } = getService$2("data-mapper");
|
2086
2423
|
ctx.body = { data: contentTypes2.map(toDto) };
|
2087
2424
|
},
|
2088
2425
|
async findContentTypesSettings(ctx) {
|
2089
|
-
const { findAllContentTypes, findConfiguration } = getService$
|
2426
|
+
const { findAllContentTypes, findConfiguration } = getService$2("content-types");
|
2090
2427
|
const contentTypes2 = await findAllContentTypes();
|
2091
2428
|
const configurations = await Promise.all(
|
2092
2429
|
contentTypes2.map(async (contentType) => {
|
@@ -2100,7 +2437,7 @@ const contentTypes = {
|
|
2100
2437
|
},
|
2101
2438
|
async findContentTypeConfiguration(ctx) {
|
2102
2439
|
const { uid: uid2 } = ctx.params;
|
2103
|
-
const contentTypeService = getService$
|
2440
|
+
const contentTypeService = getService$2("content-types");
|
2104
2441
|
const contentType = await contentTypeService.findContentType(uid2);
|
2105
2442
|
if (!contentType) {
|
2106
2443
|
return ctx.notFound("contentType.notFound");
|
@@ -2122,13 +2459,13 @@ const contentTypes = {
|
|
2122
2459
|
const { userAbility } = ctx.state;
|
2123
2460
|
const { uid: uid2 } = ctx.params;
|
2124
2461
|
const { body } = ctx.request;
|
2125
|
-
const contentTypeService = getService$
|
2126
|
-
const metricsService = getService$
|
2462
|
+
const contentTypeService = getService$2("content-types");
|
2463
|
+
const metricsService = getService$2("metrics");
|
2127
2464
|
const contentType = await contentTypeService.findContentType(uid2);
|
2128
2465
|
if (!contentType) {
|
2129
2466
|
return ctx.notFound("contentType.notFound");
|
2130
2467
|
}
|
2131
|
-
if (!getService$
|
2468
|
+
if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
|
2132
2469
|
return ctx.forbidden();
|
2133
2470
|
}
|
2134
2471
|
let input;
|
@@ -2161,10 +2498,10 @@ const contentTypes = {
|
|
2161
2498
|
};
|
2162
2499
|
const init = {
|
2163
2500
|
getInitData(ctx) {
|
2164
|
-
const { toDto } = getService$
|
2165
|
-
const { findAllComponents } = getService$
|
2166
|
-
const { getAllFieldSizes } = getService$
|
2167
|
-
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");
|
2168
2505
|
ctx.body = {
|
2169
2506
|
data: {
|
2170
2507
|
fieldSizes: getAllFieldSizes(),
|
@@ -2200,36 +2537,41 @@ const addFiltersClause = (params, filtersClause) => {
|
|
2200
2537
|
params.filters.$and.push(filtersClause);
|
2201
2538
|
};
|
2202
2539
|
const sanitizeMainField = (model, mainField, userAbility) => {
|
2203
|
-
const permissionChecker2 = getService$
|
2540
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2204
2541
|
userAbility,
|
2205
2542
|
model: model.uid
|
2206
2543
|
});
|
2207
|
-
|
2544
|
+
const isMainFieldListable = isListable(model, mainField);
|
2545
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2546
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2208
2547
|
return "id";
|
2209
2548
|
}
|
2210
|
-
if (
|
2211
|
-
|
2212
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2213
|
-
userAbility,
|
2214
|
-
model: "plugin::users-permissions.user"
|
2215
|
-
});
|
2216
|
-
if (userPermissionChecker.can.read()) {
|
2217
|
-
return "name";
|
2218
|
-
}
|
2219
|
-
}
|
2220
|
-
return "id";
|
2549
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2550
|
+
return "name";
|
2221
2551
|
}
|
2222
2552
|
return mainField;
|
2223
2553
|
};
|
2224
|
-
const addStatusToRelations = async (
|
2225
|
-
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) {
|
2226
2560
|
return relations2;
|
2227
2561
|
}
|
2228
|
-
const
|
2229
|
-
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
|
+
});
|
2230
2572
|
return relations2.map((relation) => {
|
2231
|
-
const availableStatuses =
|
2232
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2573
|
+
const availableStatuses = availableStatus.filter(
|
2574
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2233
2575
|
);
|
2234
2576
|
return {
|
2235
2577
|
...relation,
|
@@ -2250,11 +2592,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2250
2592
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2251
2593
|
const isSourceLocalized = isLocalized(sourceModel);
|
2252
2594
|
const isTargetLocalized = isLocalized(targetModel);
|
2253
|
-
let validatedLocale = locale;
|
2254
|
-
if (!targetModel || !isTargetLocalized)
|
2255
|
-
validatedLocale = void 0;
|
2256
2595
|
return {
|
2257
|
-
locale
|
2596
|
+
locale,
|
2258
2597
|
isSourceLocalized,
|
2259
2598
|
isTargetLocalized
|
2260
2599
|
};
|
@@ -2263,8 +2602,7 @@ const validateStatus = (sourceUid, status) => {
|
|
2263
2602
|
const sourceModel = strapi.getModel(sourceUid);
|
2264
2603
|
const isDP = contentTypes$1.hasDraftAndPublish;
|
2265
2604
|
const isSourceDP = isDP(sourceModel);
|
2266
|
-
if (!isSourceDP)
|
2267
|
-
return { status: void 0 };
|
2605
|
+
if (!isSourceDP) return { status: void 0 };
|
2268
2606
|
switch (status) {
|
2269
2607
|
case "published":
|
2270
2608
|
return { status: "published" };
|
@@ -2294,7 +2632,7 @@ const relations = {
|
|
2294
2632
|
ctx.request?.query?.locale
|
2295
2633
|
);
|
2296
2634
|
const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
|
2297
|
-
const permissionChecker2 = getService$
|
2635
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2298
2636
|
userAbility,
|
2299
2637
|
model
|
2300
2638
|
});
|
@@ -2319,7 +2657,7 @@ const relations = {
|
|
2319
2657
|
where.id = id;
|
2320
2658
|
}
|
2321
2659
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2322
|
-
const populate = await getService$
|
2660
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2323
2661
|
const currentEntity = await strapi.db.query(model).findOne({
|
2324
2662
|
where,
|
2325
2663
|
populate
|
@@ -2334,7 +2672,7 @@ const relations = {
|
|
2334
2672
|
}
|
2335
2673
|
entryId = currentEntity.id;
|
2336
2674
|
}
|
2337
|
-
const modelConfig = isComponent2 ? await getService$
|
2675
|
+
const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
|
2338
2676
|
const targetSchema = strapi.getModel(targetUid);
|
2339
2677
|
const mainField = flow(
|
2340
2678
|
prop(`metadatas.${targetField}.edit.mainField`),
|
@@ -2357,7 +2695,7 @@ const relations = {
|
|
2357
2695
|
attribute,
|
2358
2696
|
fieldsToSelect,
|
2359
2697
|
mainField,
|
2360
|
-
source: { schema: sourceSchema },
|
2698
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2361
2699
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2362
2700
|
sourceSchema,
|
2363
2701
|
targetSchema,
|
@@ -2379,7 +2717,8 @@ const relations = {
|
|
2379
2717
|
fieldsToSelect,
|
2380
2718
|
mainField,
|
2381
2719
|
source: {
|
2382
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2720
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2721
|
+
isLocalized: isSourceLocalized
|
2383
2722
|
},
|
2384
2723
|
target: {
|
2385
2724
|
schema: { uid: targetUid },
|
@@ -2387,7 +2726,7 @@ const relations = {
|
|
2387
2726
|
}
|
2388
2727
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2389
2728
|
const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
2390
|
-
const permissionChecker2 = getService$
|
2729
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2391
2730
|
userAbility: ctx.state.userAbility,
|
2392
2731
|
model: targetUid
|
2393
2732
|
});
|
@@ -2417,12 +2756,16 @@ const relations = {
|
|
2417
2756
|
} else {
|
2418
2757
|
where.id = id;
|
2419
2758
|
}
|
2420
|
-
|
2421
|
-
|
2759
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2760
|
+
if (!isEmpty(publishedAt)) {
|
2761
|
+
where[`${alias}.published_at`] = publishedAt;
|
2422
2762
|
}
|
2423
|
-
if (
|
2763
|
+
if (isTargetLocalized && locale) {
|
2424
2764
|
where[`${alias}.locale`] = locale;
|
2425
2765
|
}
|
2766
|
+
if (isSourceLocalized && locale) {
|
2767
|
+
where.locale = locale;
|
2768
|
+
}
|
2426
2769
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2427
2770
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2428
2771
|
}
|
@@ -2440,7 +2783,8 @@ const relations = {
|
|
2440
2783
|
id: { $notIn: uniq(idsToOmit) }
|
2441
2784
|
});
|
2442
2785
|
}
|
2443
|
-
const
|
2786
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2787
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2444
2788
|
ctx.body = {
|
2445
2789
|
...res,
|
2446
2790
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2455,29 +2799,39 @@ const relations = {
|
|
2455
2799
|
attribute,
|
2456
2800
|
targetField,
|
2457
2801
|
fieldsToSelect,
|
2458
|
-
|
2459
|
-
|
2460
|
-
}
|
2461
|
-
target: {
|
2462
|
-
schema: { uid: targetUid }
|
2463
|
-
}
|
2802
|
+
status,
|
2803
|
+
source: { schema: sourceSchema },
|
2804
|
+
target: { schema: targetSchema }
|
2464
2805
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2465
|
-
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 });
|
2466
2809
|
const dbQuery = strapi.db.query(sourceUid);
|
2467
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
|
+
}
|
2468
2823
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2469
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2824
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2470
2825
|
ordering: "desc",
|
2471
2826
|
page: ctx.request.query.page,
|
2472
|
-
pageSize: ctx.request.query.pageSize
|
2827
|
+
pageSize: ctx.request.query.pageSize,
|
2828
|
+
filters
|
2473
2829
|
});
|
2474
2830
|
const loadedIds = res.results.map((item) => item.id);
|
2475
2831
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2476
2832
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2477
2833
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2478
|
-
ordering: "desc"
|
2479
|
-
page: ctx.request.query.page,
|
2480
|
-
pageSize: ctx.request.query.pageSize
|
2834
|
+
ordering: "desc"
|
2481
2835
|
});
|
2482
2836
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2483
2837
|
ctx.body = {
|
@@ -2492,10 +2846,10 @@ const relations = {
|
|
2492
2846
|
}
|
2493
2847
|
};
|
2494
2848
|
const buildPopulateFromQuery = async (query, model) => {
|
2495
|
-
return getService$
|
2849
|
+
return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
|
2496
2850
|
};
|
2497
2851
|
const findDocument = async (query, uid2, opts = {}) => {
|
2498
|
-
const documentManager2 = getService$
|
2852
|
+
const documentManager2 = getService$2("document-manager");
|
2499
2853
|
const populate = await buildPopulateFromQuery(query, uid2);
|
2500
2854
|
return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
|
2501
2855
|
};
|
@@ -2503,13 +2857,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2503
2857
|
const { user, userAbility } = ctx.state;
|
2504
2858
|
const { model } = ctx.params;
|
2505
2859
|
const { body, query } = ctx.request;
|
2506
|
-
const documentManager2 = getService$
|
2507
|
-
const permissionChecker2 = getService$
|
2860
|
+
const documentManager2 = getService$2("document-manager");
|
2861
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2508
2862
|
if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
|
2509
2863
|
throw new errors.ForbiddenError();
|
2510
2864
|
}
|
2511
2865
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2512
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2866
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2513
2867
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2514
2868
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2515
2869
|
// Find the first document to check if it exists
|
@@ -2545,13 +2899,12 @@ const singleTypes = {
|
|
2545
2899
|
const { userAbility } = ctx.state;
|
2546
2900
|
const { model } = ctx.params;
|
2547
2901
|
const { query = {} } = ctx.request;
|
2548
|
-
const permissionChecker2 = getService$
|
2549
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2902
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2550
2903
|
if (permissionChecker2.cannot.read()) {
|
2551
2904
|
return ctx.forbidden();
|
2552
2905
|
}
|
2553
2906
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2554
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2907
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2555
2908
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2556
2909
|
if (!version) {
|
2557
2910
|
if (permissionChecker2.cannot.create()) {
|
@@ -2561,9 +2914,11 @@ const singleTypes = {
|
|
2561
2914
|
if (!document) {
|
2562
2915
|
return ctx.notFound();
|
2563
2916
|
}
|
2564
|
-
const { meta } = await
|
2917
|
+
const { meta } = await formatDocumentWithMetadata(
|
2918
|
+
permissionChecker2,
|
2565
2919
|
model,
|
2566
|
-
|
2920
|
+
// @ts-expect-error - fix types
|
2921
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2567
2922
|
{ availableLocales: true, availableStatus: false }
|
2568
2923
|
);
|
2569
2924
|
ctx.body = { data: {}, meta };
|
@@ -2573,29 +2928,28 @@ const singleTypes = {
|
|
2573
2928
|
return ctx.forbidden();
|
2574
2929
|
}
|
2575
2930
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2576
|
-
ctx.body = await
|
2931
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2577
2932
|
},
|
2578
2933
|
async createOrUpdate(ctx) {
|
2579
2934
|
const { userAbility } = ctx.state;
|
2580
2935
|
const { model } = ctx.params;
|
2581
|
-
const
|
2582
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2936
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2583
2937
|
const document = await createOrUpdateDocument(ctx);
|
2584
2938
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2585
|
-
ctx.body = await
|
2939
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2586
2940
|
},
|
2587
2941
|
async delete(ctx) {
|
2588
2942
|
const { userAbility } = ctx.state;
|
2589
2943
|
const { model } = ctx.params;
|
2590
2944
|
const { query = {} } = ctx.request;
|
2591
|
-
const documentManager2 = getService$
|
2592
|
-
const permissionChecker2 = getService$
|
2945
|
+
const documentManager2 = getService$2("document-manager");
|
2946
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2593
2947
|
if (permissionChecker2.cannot.delete()) {
|
2594
2948
|
return ctx.forbidden();
|
2595
2949
|
}
|
2596
2950
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2597
2951
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2598
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2952
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2599
2953
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2600
2954
|
populate,
|
2601
2955
|
locale
|
@@ -2617,9 +2971,8 @@ const singleTypes = {
|
|
2617
2971
|
const { userAbility } = ctx.state;
|
2618
2972
|
const { model } = ctx.params;
|
2619
2973
|
const { query = {} } = ctx.request;
|
2620
|
-
const documentManager2 = getService$
|
2621
|
-
const
|
2622
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2974
|
+
const documentManager2 = getService$2("document-manager");
|
2975
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2623
2976
|
if (permissionChecker2.cannot.publish()) {
|
2624
2977
|
return ctx.forbidden();
|
2625
2978
|
}
|
@@ -2633,11 +2986,12 @@ const singleTypes = {
|
|
2633
2986
|
if (permissionChecker2.cannot.publish(document)) {
|
2634
2987
|
throw new errors.ForbiddenError();
|
2635
2988
|
}
|
2636
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2637
|
-
|
2989
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2990
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2991
|
+
return publishResult.at(0);
|
2638
2992
|
});
|
2639
2993
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2640
|
-
ctx.body = await
|
2994
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2641
2995
|
},
|
2642
2996
|
async unpublish(ctx) {
|
2643
2997
|
const { userAbility } = ctx.state;
|
@@ -2646,9 +3000,8 @@ const singleTypes = {
|
|
2646
3000
|
body: { discardDraft, ...body },
|
2647
3001
|
query = {}
|
2648
3002
|
} = ctx.request;
|
2649
|
-
const documentManager2 = getService$
|
2650
|
-
const
|
2651
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
3003
|
+
const documentManager2 = getService$2("document-manager");
|
3004
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2652
3005
|
if (permissionChecker2.cannot.unpublish()) {
|
2653
3006
|
return ctx.forbidden();
|
2654
3007
|
}
|
@@ -2656,7 +3009,7 @@ const singleTypes = {
|
|
2656
3009
|
return ctx.forbidden();
|
2657
3010
|
}
|
2658
3011
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2659
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
3012
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2660
3013
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2661
3014
|
if (!document) {
|
2662
3015
|
return ctx.notFound();
|
@@ -2674,7 +3027,7 @@ const singleTypes = {
|
|
2674
3027
|
ctx.body = await async.pipe(
|
2675
3028
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2676
3029
|
permissionChecker2.sanitizeOutput,
|
2677
|
-
(document2) =>
|
3030
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2678
3031
|
)(document);
|
2679
3032
|
});
|
2680
3033
|
},
|
@@ -2682,14 +3035,13 @@ const singleTypes = {
|
|
2682
3035
|
const { userAbility } = ctx.state;
|
2683
3036
|
const { model } = ctx.params;
|
2684
3037
|
const { body, query = {} } = ctx.request;
|
2685
|
-
const documentManager2 = getService$
|
2686
|
-
const
|
2687
|
-
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
3038
|
+
const documentManager2 = getService$2("document-manager");
|
3039
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2688
3040
|
if (permissionChecker2.cannot.discard()) {
|
2689
3041
|
return ctx.forbidden();
|
2690
3042
|
}
|
2691
3043
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2692
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
3044
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2693
3045
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2694
3046
|
if (!document) {
|
2695
3047
|
return ctx.notFound();
|
@@ -2700,16 +3052,16 @@ const singleTypes = {
|
|
2700
3052
|
ctx.body = await async.pipe(
|
2701
3053
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2702
3054
|
permissionChecker2.sanitizeOutput,
|
2703
|
-
(document2) =>
|
3055
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2704
3056
|
)(document);
|
2705
3057
|
},
|
2706
3058
|
async countDraftRelations(ctx) {
|
2707
3059
|
const { userAbility } = ctx.state;
|
2708
3060
|
const { model } = ctx.params;
|
2709
3061
|
const { query } = ctx.request;
|
2710
|
-
const documentManager2 = getService$
|
2711
|
-
const permissionChecker2 = getService$
|
2712
|
-
const { locale } = 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);
|
2713
3065
|
if (permissionChecker2.cannot.read()) {
|
2714
3066
|
return ctx.forbidden();
|
2715
3067
|
}
|
@@ -2730,9 +3082,9 @@ const uid$1 = {
|
|
2730
3082
|
async generateUID(ctx) {
|
2731
3083
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2732
3084
|
const { query = {} } = ctx.request;
|
2733
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
3085
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2734
3086
|
await validateUIDField(contentTypeUID, field);
|
2735
|
-
const uidService = getService$
|
3087
|
+
const uidService = getService$2("uid");
|
2736
3088
|
ctx.body = {
|
2737
3089
|
data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
|
2738
3090
|
};
|
@@ -2742,9 +3094,9 @@ const uid$1 = {
|
|
2742
3094
|
ctx.request.body
|
2743
3095
|
);
|
2744
3096
|
const { query = {} } = ctx.request;
|
2745
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
3097
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2746
3098
|
await validateUIDField(contentTypeUID, field);
|
2747
|
-
const uidService = getService$
|
3099
|
+
const uidService = getService$2("uid");
|
2748
3100
|
const isAvailable = await uidService.checkUIDAvailability({
|
2749
3101
|
contentTypeUID,
|
2750
3102
|
field,
|
@@ -2765,7 +3117,8 @@ const controllers = {
|
|
2765
3117
|
relations,
|
2766
3118
|
"single-types": singleTypes,
|
2767
3119
|
uid: uid$1,
|
2768
|
-
...history.controllers ? history.controllers : {}
|
3120
|
+
...history.controllers ? history.controllers : {},
|
3121
|
+
...preview.controllers ? preview.controllers : {}
|
2769
3122
|
};
|
2770
3123
|
const keys = {
|
2771
3124
|
CONFIGURATION: "configuration"
|
@@ -2894,18 +3247,15 @@ async function syncMetadatas(configuration, schema) {
|
|
2894
3247
|
_.set(updatedMeta, ["list", "searchable"], false);
|
2895
3248
|
_.set(acc, [key], updatedMeta);
|
2896
3249
|
}
|
2897
|
-
if (!_.has(edit, "mainField"))
|
2898
|
-
return acc;
|
3250
|
+
if (!_.has(edit, "mainField")) return acc;
|
2899
3251
|
if (!isRelation$1(attr)) {
|
2900
3252
|
_.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
|
2901
3253
|
_.set(acc, [key], updatedMeta);
|
2902
3254
|
return acc;
|
2903
3255
|
}
|
2904
|
-
if (edit.mainField === "id")
|
2905
|
-
return acc;
|
3256
|
+
if (edit.mainField === "id") return acc;
|
2906
3257
|
const targetSchema = getTargetSchema(attr.targetModel);
|
2907
|
-
if (!targetSchema)
|
2908
|
-
return acc;
|
3258
|
+
if (!targetSchema) return acc;
|
2909
3259
|
if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
|
2910
3260
|
_.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
|
2911
3261
|
_.set(acc, [key], updatedMeta);
|
@@ -2916,12 +3266,12 @@ async function syncMetadatas(configuration, schema) {
|
|
2916
3266
|
return _.assign(metasWithDefaults, updatedMetas);
|
2917
3267
|
}
|
2918
3268
|
const getTargetSchema = (targetModel) => {
|
2919
|
-
return getService$
|
3269
|
+
return getService$2("content-types").findContentType(targetModel);
|
2920
3270
|
};
|
2921
3271
|
const DEFAULT_LIST_LENGTH = 4;
|
2922
3272
|
const MAX_ROW_SIZE = 12;
|
2923
3273
|
const isAllowedFieldSize = (type, size) => {
|
2924
|
-
const { getFieldSize } = getService$
|
3274
|
+
const { getFieldSize } = getService$2("field-sizes");
|
2925
3275
|
const fieldSize = getFieldSize(type);
|
2926
3276
|
if (!fieldSize.isResizable && size !== fieldSize.default) {
|
2927
3277
|
return false;
|
@@ -2929,7 +3279,7 @@ const isAllowedFieldSize = (type, size) => {
|
|
2929
3279
|
return size <= MAX_ROW_SIZE;
|
2930
3280
|
};
|
2931
3281
|
const getDefaultFieldSize = (attribute) => {
|
2932
|
-
const { hasFieldSize, getFieldSize } = getService$
|
3282
|
+
const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
|
2933
3283
|
return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
|
2934
3284
|
};
|
2935
3285
|
async function createDefaultLayouts(schema) {
|
@@ -2950,8 +3300,7 @@ function createDefaultEditLayout(schema) {
|
|
2950
3300
|
return appendToEditLayout([], keys2, schema);
|
2951
3301
|
}
|
2952
3302
|
function syncLayouts(configuration, schema) {
|
2953
|
-
if (_.isEmpty(configuration.layouts))
|
2954
|
-
return createDefaultLayouts(schema);
|
3303
|
+
if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
|
2955
3304
|
const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
|
2956
3305
|
let cleanList = list.filter((attr) => isListable(schema, attr));
|
2957
3306
|
const cleanEditRelations = editRelations.filter(
|
@@ -2962,9 +3311,8 @@ function syncLayouts(configuration, schema) {
|
|
2962
3311
|
for (const row of edit) {
|
2963
3312
|
const newRow = [];
|
2964
3313
|
for (const el of row) {
|
2965
|
-
if (!hasEditableAttribute(schema, el.name))
|
2966
|
-
|
2967
|
-
const { hasFieldSize } = getService$1("field-sizes");
|
3314
|
+
if (!hasEditableAttribute(schema, el.name)) continue;
|
3315
|
+
const { hasFieldSize } = getService$2("field-sizes");
|
2968
3316
|
const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
|
2969
3317
|
if (!isAllowedFieldSize(fieldType, el.size)) {
|
2970
3318
|
elementsToReAppend.push(el.name);
|
@@ -2994,8 +3342,7 @@ function syncLayouts(configuration, schema) {
|
|
2994
3342
|
};
|
2995
3343
|
}
|
2996
3344
|
const appendToEditLayout = (layout = [], keysToAppend, schema) => {
|
2997
|
-
if (keysToAppend.length === 0)
|
2998
|
-
return layout;
|
3345
|
+
if (keysToAppend.length === 0) return layout;
|
2999
3346
|
let currentRowIndex = Math.max(layout.length - 1, 0);
|
3000
3347
|
if (!layout[currentRowIndex]) {
|
3001
3348
|
layout[currentRowIndex] = [];
|
@@ -3104,17 +3451,17 @@ const configurationService$1 = createConfigurationService({
|
|
3104
3451
|
isComponent: true,
|
3105
3452
|
prefix: STORE_KEY_PREFIX,
|
3106
3453
|
getModels() {
|
3107
|
-
const { toContentManagerModel } = getService$
|
3454
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3108
3455
|
return mapValues(toContentManagerModel, strapi.components);
|
3109
3456
|
}
|
3110
3457
|
});
|
3111
3458
|
const components = ({ strapi: strapi2 }) => ({
|
3112
3459
|
findAllComponents() {
|
3113
|
-
const { toContentManagerModel } = getService$
|
3460
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3114
3461
|
return Object.values(strapi2.components).map(toContentManagerModel);
|
3115
3462
|
},
|
3116
3463
|
findComponent(uid2) {
|
3117
|
-
const { toContentManagerModel } = getService$
|
3464
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3118
3465
|
const component = strapi2.components[uid2];
|
3119
3466
|
return isNil$1(component) ? component : toContentManagerModel(component);
|
3120
3467
|
},
|
@@ -3165,17 +3512,17 @@ const configurationService = createConfigurationService({
|
|
3165
3512
|
storeUtils,
|
3166
3513
|
prefix: "content_types",
|
3167
3514
|
getModels() {
|
3168
|
-
const { toContentManagerModel } = getService$
|
3515
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3169
3516
|
return mapValues(toContentManagerModel, strapi.contentTypes);
|
3170
3517
|
}
|
3171
3518
|
});
|
3172
3519
|
const service = ({ strapi: strapi2 }) => ({
|
3173
3520
|
findAllContentTypes() {
|
3174
|
-
const { toContentManagerModel } = getService$
|
3521
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3175
3522
|
return Object.values(strapi2.contentTypes).map(toContentManagerModel);
|
3176
3523
|
},
|
3177
3524
|
findContentType(uid2) {
|
3178
|
-
const { toContentManagerModel } = getService$
|
3525
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3179
3526
|
const contentType = strapi2.contentTypes[uid2];
|
3180
3527
|
return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
|
3181
3528
|
},
|
@@ -3204,7 +3551,7 @@ const service = ({ strapi: strapi2 }) => ({
|
|
3204
3551
|
return this.findConfiguration(contentType);
|
3205
3552
|
},
|
3206
3553
|
findComponentsConfigurations(contentType) {
|
3207
|
-
return getService$
|
3554
|
+
return getService$2("components").findComponentsConfigurations(contentType);
|
3208
3555
|
},
|
3209
3556
|
syncConfigurations() {
|
3210
3557
|
return configurationService.syncConfigurations();
|
@@ -3385,12 +3732,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3385
3732
|
ability: userAbility,
|
3386
3733
|
model
|
3387
3734
|
});
|
3388
|
-
const
|
3735
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3736
|
+
const toSubject = (entity) => {
|
3737
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3738
|
+
};
|
3389
3739
|
const can = (action, entity, field) => {
|
3390
|
-
|
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
|
+
);
|
3391
3747
|
};
|
3392
3748
|
const cannot = (action, entity, field) => {
|
3393
|
-
|
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
|
+
);
|
3394
3756
|
};
|
3395
3757
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3396
3758
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3461,7 +3823,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3461
3823
|
return userAbility.can(action);
|
3462
3824
|
},
|
3463
3825
|
async registerPermissions() {
|
3464
|
-
const displayedContentTypes = getService$
|
3826
|
+
const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
|
3465
3827
|
const contentTypesUids = displayedContentTypes.map(prop("uid"));
|
3466
3828
|
const actions = [
|
3467
3829
|
{
|
@@ -3533,7 +3895,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3533
3895
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3534
3896
|
}
|
3535
3897
|
});
|
3536
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
|
3898
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
|
3537
3899
|
const { isAnyToMany } = strapiUtils.relations;
|
3538
3900
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
|
3539
3901
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3546,6 +3908,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
|
|
3546
3908
|
if (initialPopulate) {
|
3547
3909
|
return initialPopulate;
|
3548
3910
|
}
|
3911
|
+
if (attributeName === "localizations") {
|
3912
|
+
const validationPopulate = getPopulateForValidation(model.uid);
|
3913
|
+
return {
|
3914
|
+
populate: validationPopulate.populate
|
3915
|
+
};
|
3916
|
+
}
|
3549
3917
|
if (!isVisibleAttribute$1(model, attributeName)) {
|
3550
3918
|
return true;
|
3551
3919
|
}
|
@@ -3605,6 +3973,9 @@ const getDeepPopulate = (uid2, {
|
|
3605
3973
|
return {};
|
3606
3974
|
}
|
3607
3975
|
const model = strapi.getModel(uid2);
|
3976
|
+
if (!model) {
|
3977
|
+
return {};
|
3978
|
+
}
|
3608
3979
|
return Object.keys(model.attributes).reduce(
|
3609
3980
|
(populateAcc, attributeName) => merge(
|
3610
3981
|
populateAcc,
|
@@ -3624,6 +3995,48 @@ const getDeepPopulate = (uid2, {
|
|
3624
3995
|
{}
|
3625
3996
|
);
|
3626
3997
|
};
|
3998
|
+
const getPopulateForValidation = (uid2) => {
|
3999
|
+
const model = strapi.getModel(uid2);
|
4000
|
+
if (!model) {
|
4001
|
+
return {};
|
4002
|
+
}
|
4003
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
4004
|
+
if (isScalarAttribute(attribute)) {
|
4005
|
+
if (getDoesAttributeRequireValidation(attribute)) {
|
4006
|
+
populateAcc.fields = populateAcc.fields || [];
|
4007
|
+
populateAcc.fields.push(attributeName);
|
4008
|
+
}
|
4009
|
+
return populateAcc;
|
4010
|
+
}
|
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;
|
4019
|
+
}
|
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;
|
4029
|
+
},
|
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;
|
4038
|
+
}, {});
|
4039
|
+
};
|
3627
4040
|
const getDeepPopulateDraftCount = (uid2) => {
|
3628
4041
|
const model = strapi.getModel(uid2);
|
3629
4042
|
let hasRelations = false;
|
@@ -3631,6 +4044,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3631
4044
|
const attribute = model.attributes[attributeName];
|
3632
4045
|
switch (attribute.type) {
|
3633
4046
|
case "relation": {
|
4047
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
4048
|
+
if (isMorphRelation) {
|
4049
|
+
break;
|
4050
|
+
}
|
3634
4051
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3635
4052
|
populateAcc[attributeName] = {
|
3636
4053
|
count: true,
|
@@ -3645,22 +4062,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3645
4062
|
attribute.component
|
3646
4063
|
);
|
3647
4064
|
if (childHasRelations) {
|
3648
|
-
populateAcc[attributeName] = {
|
4065
|
+
populateAcc[attributeName] = {
|
4066
|
+
populate: populate2
|
4067
|
+
};
|
3649
4068
|
hasRelations = true;
|
3650
4069
|
}
|
3651
4070
|
break;
|
3652
4071
|
}
|
3653
4072
|
case "dynamiczone": {
|
3654
|
-
const
|
3655
|
-
const { populate:
|
3656
|
-
if (
|
4073
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
4074
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
4075
|
+
if (componentHasRelations) {
|
3657
4076
|
hasRelations = true;
|
3658
|
-
return
|
4077
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3659
4078
|
}
|
3660
4079
|
return acc;
|
3661
4080
|
}, {});
|
3662
|
-
if (!isEmpty(
|
3663
|
-
populateAcc[attributeName] = {
|
4081
|
+
if (!isEmpty(dzPopulateFragment)) {
|
4082
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3664
4083
|
}
|
3665
4084
|
break;
|
3666
4085
|
}
|
@@ -3695,7 +4114,7 @@ const getQueryPopulate = async (uid2, query) => {
|
|
3695
4114
|
return populateQuery;
|
3696
4115
|
};
|
3697
4116
|
const buildDeepPopulate = (uid2) => {
|
3698
|
-
return getService$
|
4117
|
+
return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
|
3699
4118
|
};
|
3700
4119
|
const populateBuilder = (uid2) => {
|
3701
4120
|
let getInitialPopulate = async () => {
|
@@ -3852,41 +4271,55 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3852
4271
|
"updatedBy",
|
3853
4272
|
"status"
|
3854
4273
|
];
|
3855
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
4274
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
4275
|
+
"id",
|
4276
|
+
"locale",
|
4277
|
+
"updatedAt",
|
4278
|
+
"createdAt",
|
4279
|
+
"publishedAt",
|
4280
|
+
"documentId"
|
4281
|
+
];
|
3856
4282
|
const CONTENT_MANAGER_STATUS = {
|
3857
4283
|
PUBLISHED: "published",
|
3858
4284
|
DRAFT: "draft",
|
3859
4285
|
MODIFIED: "modified"
|
3860
4286
|
};
|
3861
|
-
const
|
3862
|
-
if (!
|
4287
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
4288
|
+
if (!version || !version.updatedAt) {
|
3863
4289
|
return false;
|
3864
4290
|
}
|
3865
|
-
const
|
3866
|
-
const
|
3867
|
-
|
3868
|
-
return difference2 <= threshold;
|
4291
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
4292
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
4293
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3869
4294
|
};
|
3870
4295
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3871
4296
|
/**
|
3872
4297
|
* Returns available locales of a document for the current status
|
3873
4298
|
*/
|
3874
|
-
getAvailableLocales(uid2, version, allVersions) {
|
4299
|
+
async getAvailableLocales(uid2, version, allVersions) {
|
3875
4300
|
const versionsByLocale = groupBy("locale", allVersions);
|
3876
|
-
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
3880
|
-
|
3881
|
-
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
3885
|
-
|
3886
|
-
|
3887
|
-
|
3888
|
-
|
3889
|
-
|
4301
|
+
if (version.locale) {
|
4302
|
+
delete versionsByLocale[version.locale];
|
4303
|
+
}
|
4304
|
+
const model = strapi2.getModel(uid2);
|
4305
|
+
const mappingResult = await async.map(
|
4306
|
+
Object.values(versionsByLocale),
|
4307
|
+
async (localeVersions) => {
|
4308
|
+
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
4309
|
+
return localeVersions[0];
|
4310
|
+
}
|
4311
|
+
const draftVersion = localeVersions.find((v) => v.publishedAt === null);
|
4312
|
+
const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
|
4313
|
+
if (!draftVersion) {
|
4314
|
+
return;
|
4315
|
+
}
|
4316
|
+
return {
|
4317
|
+
...draftVersion,
|
4318
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4319
|
+
};
|
4320
|
+
}
|
4321
|
+
);
|
4322
|
+
return mappingResult.filter(Boolean);
|
3890
4323
|
},
|
3891
4324
|
/**
|
3892
4325
|
* Returns available status of a document for the current locale
|
@@ -3898,8 +4331,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3898
4331
|
const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
|
3899
4332
|
return matchLocale && matchStatus;
|
3900
4333
|
});
|
3901
|
-
if (!availableStatus)
|
3902
|
-
return availableStatus;
|
4334
|
+
if (!availableStatus) return availableStatus;
|
3903
4335
|
return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
|
3904
4336
|
},
|
3905
4337
|
/**
|
@@ -3909,50 +4341,64 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3909
4341
|
* @returns
|
3910
4342
|
*/
|
3911
4343
|
async getManyAvailableStatus(uid2, documents) {
|
3912
|
-
if (!documents.length)
|
3913
|
-
return [];
|
4344
|
+
if (!documents.length) return [];
|
3914
4345
|
const status = documents[0].publishedAt !== null ? "published" : "draft";
|
3915
|
-
const
|
3916
|
-
const
|
3917
|
-
|
3918
|
-
|
3919
|
-
|
3920
|
-
|
3921
|
-
|
3922
|
-
|
3923
|
-
|
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"]
|
3924
4357
|
});
|
3925
4358
|
},
|
3926
4359
|
getStatus(version, otherDocumentStatuses) {
|
3927
|
-
|
3928
|
-
|
3929
|
-
|
3930
|
-
|
3931
|
-
|
3932
|
-
|
3933
|
-
if (!publishedVersion) {
|
3934
|
-
return CONTENT_MANAGER_STATUS.DRAFT;
|
3935
|
-
}
|
4360
|
+
let draftVersion;
|
4361
|
+
let publishedVersion;
|
4362
|
+
if (version.publishedAt) {
|
4363
|
+
publishedVersion = version;
|
4364
|
+
} else {
|
4365
|
+
draftVersion = version;
|
3936
4366
|
}
|
3937
|
-
|
3938
|
-
|
4367
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4368
|
+
if (otherVersion?.publishedAt) {
|
4369
|
+
publishedVersion = otherVersion;
|
4370
|
+
} else if (otherVersion) {
|
4371
|
+
draftVersion = otherVersion;
|
3939
4372
|
}
|
3940
|
-
return CONTENT_MANAGER_STATUS.
|
4373
|
+
if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
|
4374
|
+
if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
|
4375
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4376
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3941
4377
|
},
|
4378
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4379
|
+
// We could refactor this so the locales are only loaded when they're
|
4380
|
+
// needed. e.g. in the bulk locale action modal.
|
3942
4381
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
3943
|
-
const
|
3944
|
-
|
3945
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
4382
|
+
const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
|
4383
|
+
const params = {
|
3946
4384
|
populate: {
|
4385
|
+
...populate,
|
4386
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3947
4387
|
createdBy: {
|
3948
4388
|
select: ["id", "firstname", "lastname", "email"]
|
3949
4389
|
},
|
3950
4390
|
updatedBy: {
|
3951
4391
|
select: ["id", "firstname", "lastname", "email"]
|
3952
4392
|
}
|
4393
|
+
},
|
4394
|
+
fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
|
4395
|
+
filters: {
|
4396
|
+
documentId: version.documentId
|
3953
4397
|
}
|
3954
|
-
}
|
3955
|
-
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) : [];
|
3956
4402
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3957
4403
|
return {
|
3958
4404
|
availableLocales: availableLocalesResult,
|
@@ -3965,13 +4411,30 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3965
4411
|
* - Available status of the document for the current locale
|
3966
4412
|
*/
|
3967
4413
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3968
|
-
if (!document)
|
3969
|
-
return
|
4414
|
+
if (!document) {
|
4415
|
+
return {
|
4416
|
+
data: document,
|
4417
|
+
meta: {
|
4418
|
+
availableLocales: [],
|
4419
|
+
availableStatus: []
|
4420
|
+
}
|
4421
|
+
};
|
4422
|
+
}
|
3970
4423
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
3971
4424
|
if (!hasDraftAndPublish) {
|
3972
4425
|
opts.availableStatus = false;
|
3973
4426
|
}
|
3974
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
|
+
}
|
3975
4438
|
return {
|
3976
4439
|
data: {
|
3977
4440
|
...document,
|
@@ -4016,26 +4479,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
4016
4479
|
}, 0);
|
4017
4480
|
};
|
4018
4481
|
const { ApplicationError } = errors;
|
4019
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
4020
4482
|
const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
|
4021
4483
|
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
|
4022
4484
|
const omitIdField = omit("id");
|
4023
|
-
const emitEvent = async (uid2, event, document) => {
|
4024
|
-
const modelDef = strapi.getModel(uid2);
|
4025
|
-
const sanitizedDocument = await sanitize.sanitizers.defaultSanitizeOutput(
|
4026
|
-
{
|
4027
|
-
schema: modelDef,
|
4028
|
-
getModel(uid22) {
|
4029
|
-
return strapi.getModel(uid22);
|
4030
|
-
}
|
4031
|
-
},
|
4032
|
-
document
|
4033
|
-
);
|
4034
|
-
strapi.eventHub.emit(event, {
|
4035
|
-
model: modelDef.modelName,
|
4036
|
-
entry: sanitizedDocument
|
4037
|
-
});
|
4038
|
-
};
|
4039
4485
|
const documentManager = ({ strapi: strapi2 }) => {
|
4040
4486
|
return {
|
4041
4487
|
async findOne(id, uid2, opts = {}) {
|
@@ -4054,6 +4500,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4054
4500
|
} else if (opts.locale && opts.locale !== "*") {
|
4055
4501
|
where.locale = opts.locale;
|
4056
4502
|
}
|
4503
|
+
if (typeof opts.isPublished === "boolean") {
|
4504
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4505
|
+
}
|
4057
4506
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4058
4507
|
},
|
4059
4508
|
async findMany(opts, uid2) {
|
@@ -4087,10 +4536,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4087
4536
|
async clone(id, body, uid2) {
|
4088
4537
|
const populate = await buildDeepPopulate(uid2);
|
4089
4538
|
const params = {
|
4090
|
-
data:
|
4091
|
-
...omitIdField(body),
|
4092
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4093
|
-
},
|
4539
|
+
data: omitIdField(body),
|
4094
4540
|
populate
|
4095
4541
|
};
|
4096
4542
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4116,70 +4562,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4116
4562
|
return {};
|
4117
4563
|
},
|
4118
4564
|
// FIXME: handle relations
|
4119
|
-
async deleteMany(
|
4120
|
-
const
|
4121
|
-
|
4122
|
-
|
4123
|
-
}
|
4124
|
-
return { count: docs.length };
|
4565
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4566
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4567
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4568
|
+
});
|
4569
|
+
return { count: deletedEntries.length };
|
4125
4570
|
},
|
4126
4571
|
async publish(id, uid2, opts = {}) {
|
4127
4572
|
const populate = await buildDeepPopulate(uid2);
|
4128
4573
|
const params = { ...opts, populate };
|
4129
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4574
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4130
4575
|
},
|
4131
|
-
async publishMany(
|
4132
|
-
|
4133
|
-
|
4134
|
-
|
4135
|
-
|
4136
|
-
|
4137
|
-
|
4138
|
-
strapi2.getModel(uid2),
|
4139
|
-
document,
|
4140
|
-
void 0,
|
4141
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4142
|
-
document
|
4143
|
-
);
|
4144
|
-
})
|
4145
|
-
);
|
4146
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4147
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4148
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4149
|
-
const populate = await buildDeepPopulate(uid2);
|
4150
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4151
|
-
where: filters,
|
4152
|
-
data
|
4153
|
-
});
|
4154
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4155
|
-
where: filters,
|
4156
|
-
populate
|
4576
|
+
async publishMany(uid2, documentIds, locale) {
|
4577
|
+
return strapi2.db.transaction(async () => {
|
4578
|
+
const results = await Promise.all(
|
4579
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4580
|
+
);
|
4581
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4582
|
+
return publishedEntitiesCount;
|
4157
4583
|
});
|
4158
|
-
await Promise.all(
|
4159
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4160
|
-
);
|
4161
|
-
return publishedEntitiesCount;
|
4162
4584
|
},
|
4163
|
-
async unpublishMany(
|
4164
|
-
|
4165
|
-
return
|
4166
|
-
|
4167
|
-
|
4168
|
-
|
4169
|
-
|
4170
|
-
const populate = await buildDeepPopulate(uid2);
|
4171
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4172
|
-
where: filters,
|
4173
|
-
data
|
4174
|
-
});
|
4175
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4176
|
-
where: filters,
|
4177
|
-
populate
|
4585
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4586
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4587
|
+
return Promise.all(
|
4588
|
+
documentIds.map(
|
4589
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4590
|
+
)
|
4591
|
+
);
|
4178
4592
|
});
|
4179
|
-
|
4180
|
-
|
4181
|
-
);
|
4182
|
-
return unpublishedEntitiesCount;
|
4593
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4594
|
+
return { count: unpublishedEntitiesCount };
|
4183
4595
|
},
|
4184
4596
|
async unpublish(id, uid2, opts = {}) {
|
4185
4597
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4204,16 +4616,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4204
4616
|
}
|
4205
4617
|
return sumDraftCounts(document, uid2);
|
4206
4618
|
},
|
4207
|
-
async countManyEntriesDraftRelations(
|
4619
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4208
4620
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4209
4621
|
if (!hasRelations) {
|
4210
4622
|
return 0;
|
4211
4623
|
}
|
4624
|
+
let localeFilter = {};
|
4625
|
+
if (locale) {
|
4626
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4627
|
+
}
|
4212
4628
|
const entities = await strapi2.db.query(uid2).findMany({
|
4213
4629
|
populate,
|
4214
4630
|
where: {
|
4215
|
-
|
4216
|
-
...
|
4631
|
+
documentId: { $in: documentIds },
|
4632
|
+
...localeFilter
|
4217
4633
|
}
|
4218
4634
|
});
|
4219
4635
|
const totalNumberDraftRelations = entities.reduce(
|
@@ -4236,7 +4652,8 @@ const services = {
|
|
4236
4652
|
permission,
|
4237
4653
|
"populate-builder": populateBuilder$1,
|
4238
4654
|
uid,
|
4239
|
-
...history.services ? history.services : {}
|
4655
|
+
...history.services ? history.services : {},
|
4656
|
+
...preview.services ? preview.services : {}
|
4240
4657
|
};
|
4241
4658
|
const index = () => {
|
4242
4659
|
return {
|