@strapi/content-manager 0.0.0-experimental.d954d57341a6623992a0d211daaec8e245c3517d → 0.0.0-experimental.dad3c50630ca4fd9eccdcbe549ee632fc572e23d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-WRPUXGd6.js → ComponentConfigurationPage-BLWQy8ru.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-WRPUXGd6.js.map → ComponentConfigurationPage-BLWQy8ru.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-gdUj_t-O.mjs → ComponentConfigurationPage-CtIa3aa2.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-gdUj_t-O.mjs.map → ComponentConfigurationPage-CtIa3aa2.mjs.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
- package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
- package/dist/_chunks/{EditConfigurationPage-BwuIPOJG.mjs → EditConfigurationPage-DsPR2DVk.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-BwuIPOJG.mjs.map → EditConfigurationPage-DsPR2DVk.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-C1vjMBgy.js → EditConfigurationPage-RQkymxCy.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-C1vjMBgy.js.map → EditConfigurationPage-RQkymxCy.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-DbcGfyqK.js → EditViewPage-B-kExt8C.js} +63 -13
- package/dist/_chunks/EditViewPage-B-kExt8C.js.map +1 -0
- package/dist/_chunks/{EditViewPage-0MiFkXa8.mjs → EditViewPage-BPyVuPfM.mjs} +63 -12
- package/dist/_chunks/EditViewPage-BPyVuPfM.mjs.map +1 -0
- package/dist/_chunks/{Field-BG1xu38N.js → Field-DPIsQRre.js} +680 -261
- package/dist/_chunks/Field-DPIsQRre.js.map +1 -0
- package/dist/_chunks/{Field-BDMSCcy5.mjs → Field-Dltnt1km.mjs} +676 -257
- package/dist/_chunks/Field-Dltnt1km.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-9BnFyUjy.js → Form-BFi4MXMT.js} +43 -22
- package/dist/_chunks/Form-BFi4MXMT.js.map +1 -0
- package/dist/_chunks/{Form-CPVWavB8.mjs → Form-C1IcWm1u.mjs} +41 -19
- package/dist/_chunks/Form-C1IcWm1u.mjs.map +1 -0
- package/dist/_chunks/{History-BVpd8LP3.mjs → History-04ChQ4pl.mjs} +108 -116
- package/dist/_chunks/History-04ChQ4pl.mjs.map +1 -0
- package/dist/_chunks/{History-BWWxLt2Z.js → History-wjcK4L0C.js} +107 -116
- package/dist/_chunks/History-wjcK4L0C.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DozVMKcR.mjs → ListConfigurationPage-BYqPYLSU.mjs} +25 -12
- package/dist/_chunks/ListConfigurationPage-BYqPYLSU.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-6swzjdAZ.js → ListConfigurationPage-CRbxIC3J.js} +25 -13
- package/dist/_chunks/ListConfigurationPage-CRbxIC3J.js.map +1 -0
- package/dist/_chunks/{ListViewPage-BlzfjS2Q.js → ListViewPage-D5NY9183.js} +121 -81
- package/dist/_chunks/ListViewPage-D5NY9183.js.map +1 -0
- package/dist/_chunks/{ListViewPage-Ds0ulgfG.mjs → ListViewPage-FU2LBuhl.mjs} +118 -77
- package/dist/_chunks/ListViewPage-FU2LBuhl.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-D2nCCWEl.js → NoContentTypePage-BgQVE_Qb.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-D2nCCWEl.js.map → NoContentTypePage-BgQVE_Qb.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-BH11kaKt.mjs → NoContentTypePage-DCKUkwb8.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-BH11kaKt.mjs.map → NoContentTypePage-DCKUkwb8.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DN_JlsU2.js → NoPermissionsPage-C5jwn70o.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DN_JlsU2.js.map → NoPermissionsPage-C5jwn70o.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BT2Tn0D_.mjs → NoPermissionsPage-jqve7C8l.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BT2Tn0D_.mjs.map → NoPermissionsPage-jqve7C8l.mjs.map} +1 -1
- package/dist/_chunks/Preview-BMYN548c.mjs +294 -0
- package/dist/_chunks/Preview-BMYN548c.mjs.map +1 -0
- package/dist/_chunks/Preview-DaOihysv.js +312 -0
- package/dist/_chunks/Preview-DaOihysv.js.map +1 -0
- package/dist/_chunks/{Relations-CcgFTcWo.js → Relations-CTGM7Hv5.js} +76 -43
- package/dist/_chunks/Relations-CTGM7Hv5.js.map +1 -0
- package/dist/_chunks/{Relations-Dnag3fhV.mjs → Relations-gscPkxjF.mjs} +76 -42
- package/dist/_chunks/Relations-gscPkxjF.mjs.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-BzQmavmK.js} +37 -18
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-BzQmavmK.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-CSxLmrh1.mjs} +37 -18
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-CSxLmrh1.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-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-CWpLBSt0.js → index-Ca7YWlAA.js} +1271 -746
- package/dist/_chunks/index-Ca7YWlAA.js.map +1 -0
- package/dist/_chunks/{index-JNNNKUHs.mjs → index-DqasUQ6Q.mjs} +1288 -763
- package/dist/_chunks/index-DqasUQ6Q.mjs.map +1 -0
- package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
- package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
- package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
- package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
- package/dist/_chunks/{layout--iHdZzRk.js → layout-BW80JSCd.js} +27 -15
- package/dist/_chunks/layout-BW80JSCd.js.map +1 -0
- package/dist/_chunks/{layout-DC503LnF.mjs → layout-W3clJSCy.mjs} +28 -15
- package/dist/_chunks/layout-W3clJSCy.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-CTje5t-a.mjs → relations-BlDkoeWh.mjs} +6 -7
- package/dist/_chunks/relations-BlDkoeWh.mjs.map +1 -0
- package/dist/_chunks/{relations-BbHizA5K.js → relations-C9Usz9k5.js} +6 -7
- package/dist/_chunks/relations-C9Usz9k5.js.map +1 -0
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -3
- package/dist/admin/src/content-manager.d.ts +3 -2
- package/dist/admin/src/exports.d.ts +2 -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 +32 -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 +2 -1
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +5 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
- package/dist/admin/src/preview/index.d.ts +4 -0
- package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
- package/dist/admin/src/preview/routes.d.ts +3 -0
- package/dist/admin/src/preview/services/preview.d.ts +3 -0
- package/dist/admin/src/router.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -20
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +765 -437
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +766 -437
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts +3 -3
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +8 -12
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +7 -6
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/preview/controllers/index.d.ts +2 -0
- package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/preview.d.ts +13 -0
- package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
- package/dist/server/src/preview/index.d.ts +4 -0
- package/dist/server/src/preview/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/index.d.ts +8 -0
- package/dist/server/src/preview/routes/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/preview.d.ts +4 -0
- package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
- package/dist/server/src/preview/services/index.d.ts +16 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts +32 -0
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview.d.ts +12 -0
- package/dist/server/src/preview/services/preview.d.ts.map +1 -0
- package/dist/server/src/preview/utils.d.ts +19 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +12 -10
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +7 -6
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts +2 -2
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/index.d.ts +1 -0
- package/dist/shared/contracts/index.d.ts.map +1 -1
- package/dist/shared/contracts/preview.d.ts +27 -0
- package/dist/shared/contracts/preview.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +4 -0
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +17 -15
- package/dist/_chunks/EditViewPage-0MiFkXa8.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DbcGfyqK.js.map +0 -1
- package/dist/_chunks/Field-BDMSCcy5.mjs.map +0 -1
- package/dist/_chunks/Field-BG1xu38N.js.map +0 -1
- package/dist/_chunks/Form-9BnFyUjy.js.map +0 -1
- package/dist/_chunks/Form-CPVWavB8.mjs.map +0 -1
- package/dist/_chunks/History-BVpd8LP3.mjs.map +0 -1
- package/dist/_chunks/History-BWWxLt2Z.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-6swzjdAZ.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DozVMKcR.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BlzfjS2Q.js.map +0 -1
- package/dist/_chunks/ListViewPage-Ds0ulgfG.mjs.map +0 -1
- package/dist/_chunks/Relations-CcgFTcWo.js.map +0 -1
- package/dist/_chunks/Relations-Dnag3fhV.mjs.map +0 -1
- package/dist/_chunks/index-CWpLBSt0.js.map +0 -1
- package/dist/_chunks/index-JNNNKUHs.mjs.map +0 -1
- package/dist/_chunks/layout--iHdZzRk.js.map +0 -1
- package/dist/_chunks/layout-DC503LnF.mjs.map +0 -1
- package/dist/_chunks/relations-BbHizA5K.js.map +0 -1
- package/dist/_chunks/relations-CTje5t-a.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1,
|
2
|
-
import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat,
|
1
|
+
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, traverseEntity, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, pagination } from "@strapi/utils";
|
2
|
+
import { pick, omit, difference, castArray, mergeWith, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
|
3
3
|
import "@strapi/types";
|
4
4
|
import * as yup from "yup";
|
5
5
|
import { scheduleJob } from "node-schedule";
|
@@ -7,10 +7,10 @@ import isNil from "lodash/isNil";
|
|
7
7
|
import _, { intersection as intersection$1, difference as difference$1 } from "lodash";
|
8
8
|
import qs from "qs";
|
9
9
|
import slugify from "@sindresorhus/slugify";
|
10
|
-
const getService$
|
10
|
+
const getService$2 = (name) => {
|
11
11
|
return strapi.plugin("content-manager").service(name);
|
12
12
|
};
|
13
|
-
function getService(strapi2, name) {
|
13
|
+
function getService$1(strapi2, name) {
|
14
14
|
return strapi2.service(`plugin::content-manager.${name}`);
|
15
15
|
}
|
16
16
|
const historyRestoreVersionSchema = yup.object().shape({
|
@@ -46,7 +46,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
46
46
|
if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
|
47
47
|
throw new errors.ForbiddenError("contentType and documentId are required");
|
48
48
|
}
|
49
|
-
const permissionChecker2 = getService$
|
49
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
50
50
|
userAbility: ctx.state.userAbility,
|
51
51
|
model: ctx.query.contentType
|
52
52
|
});
|
@@ -54,7 +54,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
54
54
|
return ctx.forbidden();
|
55
55
|
}
|
56
56
|
const query = await permissionChecker2.sanitizeQuery(ctx.query);
|
57
|
-
const { results, pagination: pagination2 } = await getService(strapi2, "history").findVersionsPage({
|
57
|
+
const { results, pagination: pagination2 } = await getService$1(strapi2, "history").findVersionsPage({
|
58
58
|
query: {
|
59
59
|
...query,
|
60
60
|
...getValidPagination({ page: query.page, pageSize: query.pageSize })
|
@@ -79,14 +79,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
79
79
|
async restoreVersion(ctx) {
|
80
80
|
const request = ctx.request;
|
81
81
|
await validateRestoreVersion(request.body, "contentType is required");
|
82
|
-
const permissionChecker2 = getService$
|
82
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
83
83
|
userAbility: ctx.state.userAbility,
|
84
84
|
model: request.body.contentType
|
85
85
|
});
|
86
86
|
if (permissionChecker2.cannot.update()) {
|
87
87
|
throw new errors.ForbiddenError();
|
88
88
|
}
|
89
|
-
const restoredDocument = await getService(strapi2, "history").restoreVersion(
|
89
|
+
const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
|
90
90
|
request.params.versionId
|
91
91
|
);
|
92
92
|
return {
|
@@ -95,7 +95,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
95
95
|
}
|
96
96
|
};
|
97
97
|
};
|
98
|
-
const controllers$
|
98
|
+
const controllers$2 = {
|
99
99
|
"history-version": createHistoryVersionController
|
100
100
|
/**
|
101
101
|
* Casting is needed because the types aren't aware that Strapi supports
|
@@ -141,8 +141,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
141
141
|
};
|
142
142
|
const getRelationRestoreValue = async (versionRelationData, attribute) => {
|
143
143
|
if (Array.isArray(versionRelationData)) {
|
144
|
-
if (versionRelationData.length === 0)
|
145
|
-
return versionRelationData;
|
144
|
+
if (versionRelationData.length === 0) return versionRelationData;
|
146
145
|
const existingAndMissingRelations = await Promise.all(
|
147
146
|
versionRelationData.map((relation) => {
|
148
147
|
return strapi2.documents(attribute.target).findOne({
|
@@ -151,19 +150,16 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
151
150
|
});
|
152
151
|
})
|
153
152
|
);
|
154
|
-
return existingAndMissingRelations.filter(
|
155
|
-
(relation) => relation !== null
|
156
|
-
);
|
153
|
+
return existingAndMissingRelations.filter((relation) => relation !== null);
|
157
154
|
}
|
158
155
|
return strapi2.documents(attribute.target).findOne({
|
159
156
|
documentId: versionRelationData.documentId,
|
160
157
|
locale: versionRelationData.locale || void 0
|
161
158
|
});
|
162
159
|
};
|
163
|
-
const getMediaRestoreValue = async (versionRelationData
|
164
|
-
if (
|
160
|
+
const getMediaRestoreValue = async (versionRelationData) => {
|
161
|
+
if (Array.isArray(versionRelationData)) {
|
165
162
|
const existingAndMissingMedias = await Promise.all(
|
166
|
-
// @ts-expect-error Fix the type definitions so this isn't any
|
167
163
|
versionRelationData.map((media) => {
|
168
164
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
|
169
165
|
})
|
@@ -173,10 +169,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
173
169
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
174
170
|
};
|
175
171
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
172
|
+
const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
|
176
173
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
174
|
+
const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
|
177
175
|
const getLocaleDictionary = async () => {
|
178
|
-
if (!localesService)
|
179
|
-
return {};
|
176
|
+
if (!localesService) return {};
|
180
177
|
const locales = await localesService.find() || [];
|
181
178
|
return locales.reduce(
|
182
179
|
(acc, locale) => {
|
@@ -200,31 +197,53 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
200
197
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
201
198
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
202
199
|
};
|
203
|
-
const
|
200
|
+
const getComponentFields = (componentUID) => {
|
201
|
+
return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
|
202
|
+
(fieldsAcc, [key, attribute]) => {
|
203
|
+
if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
|
204
|
+
fieldsAcc.push(key);
|
205
|
+
}
|
206
|
+
return fieldsAcc;
|
207
|
+
},
|
208
|
+
[]
|
209
|
+
);
|
210
|
+
};
|
211
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
204
212
|
const model = strapi2.getModel(uid2);
|
205
213
|
const attributes = Object.entries(model.attributes);
|
214
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
206
215
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
207
216
|
switch (attribute.type) {
|
208
217
|
case "relation": {
|
218
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
219
|
+
if (isMorphRelation) {
|
220
|
+
break;
|
221
|
+
}
|
209
222
|
const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
|
210
223
|
if (isVisible2) {
|
211
|
-
acc[attributeName] = {
|
224
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
212
225
|
}
|
213
226
|
break;
|
214
227
|
}
|
215
228
|
case "media": {
|
216
|
-
acc[attributeName] = {
|
229
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
217
230
|
break;
|
218
231
|
}
|
219
232
|
case "component": {
|
220
233
|
const populate = getDeepPopulate2(attribute.component);
|
221
|
-
acc[attributeName] = {
|
234
|
+
acc[attributeName] = {
|
235
|
+
populate,
|
236
|
+
[fieldSelector]: getComponentFields(attribute.component)
|
237
|
+
};
|
222
238
|
break;
|
223
239
|
}
|
224
240
|
case "dynamiczone": {
|
225
241
|
const populatedComponents = (attribute.components || []).reduce(
|
226
242
|
(acc2, componentUID) => {
|
227
|
-
acc2[componentUID] = {
|
243
|
+
acc2[componentUID] = {
|
244
|
+
populate: getDeepPopulate2(componentUID),
|
245
|
+
[fieldSelector]: getComponentFields(componentUID)
|
246
|
+
};
|
228
247
|
return acc2;
|
229
248
|
},
|
230
249
|
{}
|
@@ -286,6 +305,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
286
305
|
getRelationRestoreValue,
|
287
306
|
getMediaRestoreValue,
|
288
307
|
getDefaultLocale,
|
308
|
+
isLocalizedContentType,
|
289
309
|
getLocaleDictionary,
|
290
310
|
getRetentionDays,
|
291
311
|
getVersionStatus,
|
@@ -308,7 +328,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
308
328
|
});
|
309
329
|
},
|
310
330
|
async findVersionsPage(params) {
|
311
|
-
const
|
331
|
+
const schema = strapi2.getModel(params.query.contentType);
|
332
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(schema);
|
333
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
334
|
+
let locale = null;
|
335
|
+
if (isLocalizedContentType) {
|
336
|
+
locale = params.query.locale || defaultLocale;
|
337
|
+
}
|
312
338
|
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
313
339
|
query.findPage({
|
314
340
|
...params.query,
|
@@ -324,78 +350,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
324
350
|
}),
|
325
351
|
serviceUtils.getLocaleDictionary()
|
326
352
|
]);
|
327
|
-
const
|
328
|
-
|
329
|
-
async (
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
model: "plugin::upload.file"
|
336
|
-
});
|
337
|
-
const response = await serviceUtils.buildMediaResponse(attributeValues);
|
338
|
-
const sanitizedResults = await Promise.all(
|
339
|
-
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
340
|
-
);
|
341
|
-
return {
|
342
|
-
...await currentDataWithRelations,
|
343
|
-
[attributeKey]: {
|
344
|
-
results: sanitizedResults,
|
345
|
-
meta: response.meta
|
346
|
-
}
|
347
|
-
};
|
353
|
+
const populateEntry = async (entry) => {
|
354
|
+
return traverseEntity(
|
355
|
+
async (options, utils) => {
|
356
|
+
if (!options.attribute) return;
|
357
|
+
if (!options.value) return;
|
358
|
+
const currentValue = Array.isArray(options.value) ? options.value : [options.value];
|
359
|
+
if (options.attribute.type === "component") {
|
360
|
+
utils.remove("id");
|
348
361
|
}
|
349
|
-
if (
|
350
|
-
|
362
|
+
if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
|
363
|
+
options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
|
364
|
+
if (options.attribute.target === "admin::user") {
|
351
365
|
const adminUsers = await Promise.all(
|
352
|
-
|
366
|
+
currentValue.map((userToPopulate) => {
|
353
367
|
if (userToPopulate == null) {
|
354
368
|
return null;
|
355
369
|
}
|
356
|
-
return strapi2.query("admin::user").findOne({
|
370
|
+
return strapi2.query("admin::user").findOne({
|
371
|
+
where: {
|
372
|
+
...userToPopulate.id ? { id: userToPopulate.id } : {},
|
373
|
+
...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
|
374
|
+
}
|
375
|
+
});
|
357
376
|
})
|
358
377
|
);
|
359
|
-
|
360
|
-
...await currentDataWithRelations,
|
361
|
-
/**
|
362
|
-
* Ideally we would return the same "{results: [], meta: {}}" shape, however,
|
363
|
-
* when sanitizing the data as a whole in the controller before sending to the client,
|
364
|
-
* the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
|
365
|
-
*/
|
366
|
-
[attributeKey]: adminUsers
|
367
|
-
};
|
378
|
+
utils.set(options.key, adminUsers);
|
368
379
|
}
|
369
|
-
const permissionChecker2 = getService$
|
380
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
370
381
|
userAbility: params.state.userAbility,
|
371
|
-
model:
|
382
|
+
model: options.attribute.target
|
372
383
|
});
|
373
384
|
const response = await serviceUtils.buildRelationReponse(
|
374
|
-
|
375
|
-
|
385
|
+
currentValue,
|
386
|
+
options.attribute
|
376
387
|
);
|
377
388
|
const sanitizedResults = await Promise.all(
|
378
389
|
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
379
390
|
);
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
meta: response.meta
|
385
|
-
}
|
386
|
-
};
|
391
|
+
utils.set(options.key, {
|
392
|
+
results: sanitizedResults,
|
393
|
+
meta: response.meta
|
394
|
+
});
|
387
395
|
}
|
388
|
-
|
396
|
+
if (options.attribute.type === "media") {
|
397
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
398
|
+
userAbility: params.state.userAbility,
|
399
|
+
model: "plugin::upload.file"
|
400
|
+
});
|
401
|
+
const response = await serviceUtils.buildMediaResponse(currentValue);
|
402
|
+
const sanitizedResults = await Promise.all(
|
403
|
+
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
404
|
+
);
|
405
|
+
utils.set(options.key, {
|
406
|
+
results: sanitizedResults,
|
407
|
+
meta: response.meta
|
408
|
+
});
|
409
|
+
}
|
410
|
+
},
|
411
|
+
{
|
412
|
+
schema,
|
413
|
+
getModel: strapi2.getModel.bind(strapi2)
|
389
414
|
},
|
390
|
-
|
415
|
+
entry.data
|
391
416
|
);
|
392
|
-
return entryWithRelations;
|
393
417
|
};
|
394
418
|
const formattedResults = await Promise.all(
|
395
419
|
results.map(async (result) => {
|
396
420
|
return {
|
397
421
|
...result,
|
398
|
-
data: await
|
422
|
+
data: await populateEntry(result),
|
399
423
|
meta: {
|
400
424
|
unknownAttributes: serviceUtils.getSchemaAttributesDiff(
|
401
425
|
result.schema,
|
@@ -426,30 +450,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
426
450
|
// Clone to avoid mutating the original version data
|
427
451
|
structuredClone(version.data)
|
428
452
|
);
|
429
|
-
const
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
453
|
+
const schema = structuredClone(version.schema);
|
454
|
+
schema.attributes = omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
|
455
|
+
const dataWithoutMissingRelations = await traverseEntity(
|
456
|
+
async (options, utils) => {
|
457
|
+
if (!options.attribute) return;
|
458
|
+
if (options.attribute.type === "component") {
|
459
|
+
utils.remove("id");
|
460
|
+
if (options.attribute.repeatable && options.value === null) {
|
461
|
+
utils.set(options.key, []);
|
462
|
+
}
|
439
463
|
}
|
440
|
-
if (attribute.type === "
|
441
|
-
|
442
|
-
|
443
|
-
|
464
|
+
if (options.attribute.type === "dynamiczone") {
|
465
|
+
if (options.value === null) {
|
466
|
+
utils.set(options.key, []);
|
467
|
+
}
|
444
468
|
}
|
445
|
-
if (attribute.type === "
|
446
|
-
|
447
|
-
|
469
|
+
if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
|
470
|
+
options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
|
471
|
+
if (!options.value) return;
|
472
|
+
const data2 = await serviceUtils.getRelationRestoreValue(
|
473
|
+
options.value,
|
474
|
+
options.attribute
|
475
|
+
);
|
476
|
+
utils.set(options.key, data2);
|
477
|
+
}
|
478
|
+
if (options.attribute.type === "media") {
|
479
|
+
if (!options.value) return;
|
480
|
+
const data2 = await serviceUtils.getMediaRestoreValue(
|
481
|
+
options.value
|
482
|
+
);
|
483
|
+
utils.set(options.key, data2);
|
448
484
|
}
|
449
|
-
return previousRelationAttributes;
|
450
485
|
},
|
451
|
-
|
452
|
-
|
486
|
+
{
|
487
|
+
schema,
|
488
|
+
getModel: strapi2.getModel.bind(strapi2)
|
489
|
+
},
|
490
|
+
dataWithoutAddedAttributes
|
453
491
|
);
|
454
492
|
const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
|
455
493
|
const restoredDocument = await strapi2.documents(version.contentType).update({
|
@@ -464,13 +502,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
464
502
|
}
|
465
503
|
};
|
466
504
|
};
|
505
|
+
const shouldCreateHistoryVersion = (context) => {
|
506
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
507
|
+
return false;
|
508
|
+
}
|
509
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
510
|
+
return false;
|
511
|
+
}
|
512
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
513
|
+
return false;
|
514
|
+
}
|
515
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
516
|
+
return false;
|
517
|
+
}
|
518
|
+
return true;
|
519
|
+
};
|
520
|
+
const getSchemas = (uid2) => {
|
521
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
522
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
523
|
+
(currentComponentSchemas, key) => {
|
524
|
+
const fieldSchema = attributesSchema[key];
|
525
|
+
if (fieldSchema.type === "component") {
|
526
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
527
|
+
return {
|
528
|
+
...currentComponentSchemas,
|
529
|
+
[fieldSchema.component]: componentSchema
|
530
|
+
};
|
531
|
+
}
|
532
|
+
return currentComponentSchemas;
|
533
|
+
},
|
534
|
+
{}
|
535
|
+
);
|
536
|
+
return {
|
537
|
+
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
538
|
+
componentsSchemas
|
539
|
+
};
|
540
|
+
};
|
467
541
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
468
542
|
const state = {
|
469
543
|
deleteExpiredJob: null,
|
470
544
|
isInitialized: false
|
471
545
|
};
|
472
|
-
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
473
|
-
const historyService = getService(strapi2, "history");
|
474
546
|
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
475
547
|
return {
|
476
548
|
async bootstrap() {
|
@@ -478,76 +550,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
478
550
|
return;
|
479
551
|
}
|
480
552
|
strapi2.documents.use(async (context, next) => {
|
481
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
482
|
-
return next();
|
483
|
-
}
|
484
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
485
|
-
return next();
|
486
|
-
}
|
487
|
-
if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
488
|
-
return next();
|
489
|
-
}
|
490
|
-
const contentTypeUid = context.contentType.uid;
|
491
|
-
if (!contentTypeUid.startsWith("api::")) {
|
492
|
-
return next();
|
493
|
-
}
|
494
553
|
const result = await next();
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
554
|
+
if (!shouldCreateHistoryVersion(context)) {
|
555
|
+
return result;
|
556
|
+
}
|
557
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
499
558
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
500
|
-
const
|
501
|
-
if (
|
502
|
-
|
503
|
-
"[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
|
504
|
-
);
|
505
|
-
return next();
|
559
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
560
|
+
if (!locales.length) {
|
561
|
+
return result;
|
506
562
|
}
|
507
|
-
const
|
508
|
-
|
509
|
-
|
510
|
-
|
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
|
+
)
|
511
578
|
});
|
512
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
513
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
514
|
-
const componentsSchemas = Object.keys(
|
515
|
-
attributesSchema
|
516
|
-
).reduce((currentComponentSchemas, key) => {
|
517
|
-
const fieldSchema = attributesSchema[key];
|
518
|
-
if (fieldSchema.type === "component") {
|
519
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
520
|
-
return {
|
521
|
-
...currentComponentSchemas,
|
522
|
-
[fieldSchema.component]: componentSchema
|
523
|
-
};
|
524
|
-
}
|
525
|
-
return currentComponentSchemas;
|
526
|
-
}, {});
|
527
579
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
528
|
-
onCommit(() => {
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
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
|
+
}
|
538
592
|
});
|
539
593
|
});
|
540
594
|
return result;
|
541
595
|
});
|
542
|
-
state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
|
596
|
+
state.deleteExpiredJob = scheduleJob("historyDaily", "0 0 * * *", () => {
|
543
597
|
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
544
598
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
545
|
-
query.deleteMany({
|
599
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
546
600
|
where: {
|
547
601
|
created_at: {
|
548
|
-
$lt: expirationDate
|
602
|
+
$lt: expirationDate
|
549
603
|
}
|
550
604
|
}
|
605
|
+
}).catch((error) => {
|
606
|
+
if (error instanceof Error) {
|
607
|
+
strapi2.log.error("Error deleting expired history versions", error.message);
|
608
|
+
}
|
551
609
|
});
|
552
610
|
});
|
553
611
|
state.isInitialized = true;
|
@@ -559,17 +617,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
559
617
|
}
|
560
618
|
};
|
561
619
|
};
|
562
|
-
const services$
|
620
|
+
const services$2 = {
|
563
621
|
history: createHistoryService,
|
564
622
|
lifecycles: createLifecyclesService
|
565
623
|
};
|
566
|
-
const info = { pluginName: "content-manager", type: "admin" };
|
624
|
+
const info$1 = { pluginName: "content-manager", type: "admin" };
|
567
625
|
const historyVersionRouter = {
|
568
626
|
type: "admin",
|
569
627
|
routes: [
|
570
628
|
{
|
571
629
|
method: "GET",
|
572
|
-
info,
|
630
|
+
info: info$1,
|
573
631
|
path: "/history-versions",
|
574
632
|
handler: "history-version.findMany",
|
575
633
|
config: {
|
@@ -578,7 +636,7 @@ const historyVersionRouter = {
|
|
578
636
|
},
|
579
637
|
{
|
580
638
|
method: "PUT",
|
581
|
-
info,
|
639
|
+
info: info$1,
|
582
640
|
path: "/history-versions/:versionId/restore",
|
583
641
|
handler: "history-version.restoreVersion",
|
584
642
|
config: {
|
@@ -587,7 +645,7 @@ const historyVersionRouter = {
|
|
587
645
|
}
|
588
646
|
]
|
589
647
|
};
|
590
|
-
const routes$
|
648
|
+
const routes$2 = {
|
591
649
|
"history-version": historyVersionRouter
|
592
650
|
};
|
593
651
|
const historyVersion = {
|
@@ -634,21 +692,21 @@ const historyVersion = {
|
|
634
692
|
}
|
635
693
|
}
|
636
694
|
};
|
637
|
-
const getFeature = () => {
|
695
|
+
const getFeature$1 = () => {
|
638
696
|
if (strapi.ee.features.isEnabled("cms-content-history")) {
|
639
697
|
return {
|
640
698
|
register({ strapi: strapi2 }) {
|
641
699
|
strapi2.get("models").add(historyVersion);
|
642
700
|
},
|
643
701
|
bootstrap({ strapi: strapi2 }) {
|
644
|
-
getService(strapi2, "lifecycles").bootstrap();
|
702
|
+
getService$1(strapi2, "lifecycles").bootstrap();
|
645
703
|
},
|
646
704
|
destroy({ strapi: strapi2 }) {
|
647
|
-
getService(strapi2, "lifecycles").destroy();
|
705
|
+
getService$1(strapi2, "lifecycles").destroy();
|
648
706
|
},
|
649
|
-
controllers: controllers$
|
650
|
-
services: services$
|
651
|
-
routes: routes$
|
707
|
+
controllers: controllers$2,
|
708
|
+
services: services$2,
|
709
|
+
routes: routes$2
|
652
710
|
};
|
653
711
|
}
|
654
712
|
return {
|
@@ -657,9 +715,201 @@ const getFeature = () => {
|
|
657
715
|
}
|
658
716
|
};
|
659
717
|
};
|
660
|
-
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();
|
661
910
|
const register = async ({ strapi: strapi2 }) => {
|
662
911
|
await history.register?.({ strapi: strapi2 });
|
912
|
+
await preview.register?.({ strapi: strapi2 });
|
663
913
|
};
|
664
914
|
const ALLOWED_WEBHOOK_EVENTS = {
|
665
915
|
ENTRY_PUBLISH: "entry.publish",
|
@@ -669,11 +919,12 @@ const bootstrap = async () => {
|
|
669
919
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
670
920
|
strapi.get("webhookStore").addAllowedEvent(key, value);
|
671
921
|
});
|
672
|
-
getService$
|
673
|
-
await getService$
|
674
|
-
await getService$
|
675
|
-
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();
|
676
926
|
await history.bootstrap?.({ strapi });
|
927
|
+
await preview.bootstrap?.({ strapi });
|
677
928
|
};
|
678
929
|
const destroy = async ({ strapi: strapi2 }) => {
|
679
930
|
await history.destroy?.({ strapi: strapi2 });
|
@@ -1163,7 +1414,8 @@ const admin = {
|
|
1163
1414
|
};
|
1164
1415
|
const routes = {
|
1165
1416
|
admin,
|
1166
|
-
...history.routes ? history.routes : {}
|
1417
|
+
...history.routes ? history.routes : {},
|
1418
|
+
...preview.routes ? preview.routes : {}
|
1167
1419
|
};
|
1168
1420
|
const hasPermissionsSchema = yup$1.object({
|
1169
1421
|
actions: yup$1.array().of(yup$1.string()),
|
@@ -1174,6 +1426,11 @@ const { createPolicy } = policy;
|
|
1174
1426
|
const hasPermissions = createPolicy({
|
1175
1427
|
name: "plugin::content-manager.hasPermissions",
|
1176
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
|
+
*/
|
1177
1434
|
handler(ctx, config = {}) {
|
1178
1435
|
const { actions = [], hasAtLeastOne = false } = config;
|
1179
1436
|
const { userAbility } = ctx.state;
|
@@ -1221,8 +1478,7 @@ const isSortable = (schema, name) => {
|
|
1221
1478
|
if (!_.has(schema.attributes, name)) {
|
1222
1479
|
return false;
|
1223
1480
|
}
|
1224
|
-
if (schema.modelType === "component" && name === "id")
|
1225
|
-
return false;
|
1481
|
+
if (schema.modelType === "component" && name === "id") return false;
|
1226
1482
|
const attribute = schema.attributes[name];
|
1227
1483
|
if (NON_SORTABLES.includes(attribute.type)) {
|
1228
1484
|
return false;
|
@@ -1367,8 +1623,7 @@ const createDefaultSettings = async (schema) => {
|
|
1367
1623
|
};
|
1368
1624
|
};
|
1369
1625
|
const syncSettings = async (configuration, schema) => {
|
1370
|
-
if (isEmpty(configuration.settings))
|
1371
|
-
return createDefaultSettings(schema);
|
1626
|
+
if (isEmpty(configuration.settings)) return createDefaultSettings(schema);
|
1372
1627
|
const defaultField = getDefaultMainField(schema);
|
1373
1628
|
const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
|
1374
1629
|
return {
|
@@ -1415,7 +1670,7 @@ const createMetadasSchema = (schema) => {
|
|
1415
1670
|
if (!value) {
|
1416
1671
|
return yup$1.string();
|
1417
1672
|
}
|
1418
|
-
const targetSchema = getService$
|
1673
|
+
const targetSchema = getService$2("content-types").findContentType(
|
1419
1674
|
schema.attributes[key].targetModel
|
1420
1675
|
);
|
1421
1676
|
if (!targetSchema) {
|
@@ -1544,8 +1799,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1544
1799
|
}
|
1545
1800
|
switch (attribute.type) {
|
1546
1801
|
case "relation": {
|
1547
|
-
if (canCreate(attributePath))
|
1548
|
-
return body2;
|
1802
|
+
if (canCreate(attributePath)) return body2;
|
1549
1803
|
return set(attributePath, { set: [] }, body2);
|
1550
1804
|
}
|
1551
1805
|
case "component": {
|
@@ -1555,8 +1809,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1555
1809
|
]);
|
1556
1810
|
}
|
1557
1811
|
default: {
|
1558
|
-
if (canCreate(attributePath))
|
1559
|
-
return body2;
|
1812
|
+
if (canCreate(attributePath)) return body2;
|
1560
1813
|
return set(attributePath, null, body2);
|
1561
1814
|
}
|
1562
1815
|
}
|
@@ -1567,9 +1820,11 @@ const multipleLocaleSchema = yup$1.lazy(
|
|
1567
1820
|
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1568
1821
|
);
|
1569
1822
|
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1570
|
-
const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
|
1823
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1571
1824
|
const { allowMultipleLocales } = opts;
|
1572
|
-
const { locale, status, ...rest } = request || {};
|
1825
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1826
|
+
const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1827
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1573
1828
|
const schema = yup$1.object().shape({
|
1574
1829
|
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1575
1830
|
status: statusSchema
|
@@ -1582,7 +1837,7 @@ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales
|
|
1582
1837
|
}
|
1583
1838
|
};
|
1584
1839
|
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1585
|
-
const documentMetadata2 = getService$
|
1840
|
+
const documentMetadata2 = getService$2("document-metadata");
|
1586
1841
|
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1587
1842
|
let {
|
1588
1843
|
meta: { availableLocales, availableStatus }
|
@@ -1608,8 +1863,8 @@ const createDocument = async (ctx, opts) => {
|
|
1608
1863
|
const { userAbility, user } = ctx.state;
|
1609
1864
|
const { model } = ctx.params;
|
1610
1865
|
const { body } = ctx.request;
|
1611
|
-
const documentManager2 = getService$
|
1612
|
-
const permissionChecker2 = getService$
|
1866
|
+
const documentManager2 = getService$2("document-manager");
|
1867
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1613
1868
|
if (permissionChecker2.cannot.create()) {
|
1614
1869
|
throw new errors.ForbiddenError();
|
1615
1870
|
}
|
@@ -1617,7 +1872,7 @@ const createDocument = async (ctx, opts) => {
|
|
1617
1872
|
const setCreator = setCreatorFields({ user });
|
1618
1873
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1619
1874
|
const sanitizedBody = await sanitizeFn(body);
|
1620
|
-
const { locale, status
|
1875
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1621
1876
|
return documentManager2.create(model, {
|
1622
1877
|
data: sanitizedBody,
|
1623
1878
|
locale,
|
@@ -1629,14 +1884,14 @@ const updateDocument = async (ctx, opts) => {
|
|
1629
1884
|
const { userAbility, user } = ctx.state;
|
1630
1885
|
const { id, model } = ctx.params;
|
1631
1886
|
const { body } = ctx.request;
|
1632
|
-
const documentManager2 = getService$
|
1633
|
-
const permissionChecker2 = getService$
|
1887
|
+
const documentManager2 = getService$2("document-manager");
|
1888
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1634
1889
|
if (permissionChecker2.cannot.update()) {
|
1635
1890
|
throw new errors.ForbiddenError();
|
1636
1891
|
}
|
1637
1892
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1638
|
-
const populate = await getService$
|
1639
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1893
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1894
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1640
1895
|
const [documentVersion, documentExists] = await Promise.all([
|
1641
1896
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1642
1897
|
documentManager2.exists(model, id)
|
@@ -1652,7 +1907,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1652
1907
|
throw new errors.ForbiddenError();
|
1653
1908
|
}
|
1654
1909
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1655
|
-
const setCreator = setCreatorFields({ user, isEdition: true });
|
1910
|
+
const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
|
1656
1911
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1657
1912
|
const sanitizedBody = await sanitizeFn(body);
|
1658
1913
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1666,15 +1921,15 @@ const collectionTypes = {
|
|
1666
1921
|
const { userAbility } = ctx.state;
|
1667
1922
|
const { model } = ctx.params;
|
1668
1923
|
const { query } = ctx.request;
|
1669
|
-
const documentMetadata2 = getService$
|
1670
|
-
const documentManager2 = getService$
|
1671
|
-
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 });
|
1672
1927
|
if (permissionChecker2.cannot.read()) {
|
1673
1928
|
return ctx.forbidden();
|
1674
1929
|
}
|
1675
1930
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1676
|
-
const populate = await getService$
|
1677
|
-
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
1931
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1932
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1678
1933
|
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1679
1934
|
{ ...permissionQuery, populate, locale, status },
|
1680
1935
|
model
|
@@ -1702,14 +1957,14 @@ const collectionTypes = {
|
|
1702
1957
|
async findOne(ctx) {
|
1703
1958
|
const { userAbility } = ctx.state;
|
1704
1959
|
const { model, id } = ctx.params;
|
1705
|
-
const documentManager2 = getService$
|
1706
|
-
const permissionChecker2 = getService$
|
1960
|
+
const documentManager2 = getService$2("document-manager");
|
1961
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1707
1962
|
if (permissionChecker2.cannot.read()) {
|
1708
1963
|
return ctx.forbidden();
|
1709
1964
|
}
|
1710
1965
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1711
|
-
const populate = await getService$
|
1712
|
-
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);
|
1713
1968
|
const version = await documentManager2.findOne(id, model, {
|
1714
1969
|
populate,
|
1715
1970
|
locale,
|
@@ -1724,7 +1979,7 @@ const collectionTypes = {
|
|
1724
1979
|
permissionChecker2,
|
1725
1980
|
model,
|
1726
1981
|
// @ts-expect-error TODO: fix
|
1727
|
-
{ id, locale, publishedAt: null },
|
1982
|
+
{ documentId: id, locale, publishedAt: null },
|
1728
1983
|
{ availableLocales: true, availableStatus: false }
|
1729
1984
|
);
|
1730
1985
|
ctx.body = { data: {}, meta };
|
@@ -1739,7 +1994,7 @@ const collectionTypes = {
|
|
1739
1994
|
async create(ctx) {
|
1740
1995
|
const { userAbility } = ctx.state;
|
1741
1996
|
const { model } = ctx.params;
|
1742
|
-
const permissionChecker2 = getService$
|
1997
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1743
1998
|
const [totalEntries, document] = await Promise.all([
|
1744
1999
|
strapi.db.query(model).count(),
|
1745
2000
|
createDocument(ctx)
|
@@ -1760,7 +2015,7 @@ const collectionTypes = {
|
|
1760
2015
|
async update(ctx) {
|
1761
2016
|
const { userAbility } = ctx.state;
|
1762
2017
|
const { model } = ctx.params;
|
1763
|
-
const permissionChecker2 = getService$
|
2018
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1764
2019
|
const updatedVersion = await updateDocument(ctx);
|
1765
2020
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1766
2021
|
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
@@ -1769,14 +2024,14 @@ const collectionTypes = {
|
|
1769
2024
|
const { userAbility, user } = ctx.state;
|
1770
2025
|
const { model, sourceId: id } = ctx.params;
|
1771
2026
|
const { body } = ctx.request;
|
1772
|
-
const documentManager2 = getService$
|
1773
|
-
const permissionChecker2 = getService$
|
2027
|
+
const documentManager2 = getService$2("document-manager");
|
2028
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1774
2029
|
if (permissionChecker2.cannot.create()) {
|
1775
2030
|
return ctx.forbidden();
|
1776
2031
|
}
|
1777
2032
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1778
|
-
const populate = await getService$
|
1779
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2033
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2034
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1780
2035
|
const document = await documentManager2.findOne(id, model, {
|
1781
2036
|
populate,
|
1782
2037
|
locale,
|
@@ -1814,14 +2069,14 @@ const collectionTypes = {
|
|
1814
2069
|
async delete(ctx) {
|
1815
2070
|
const { userAbility } = ctx.state;
|
1816
2071
|
const { id, model } = ctx.params;
|
1817
|
-
const documentManager2 = getService$
|
1818
|
-
const permissionChecker2 = getService$
|
2072
|
+
const documentManager2 = getService$2("document-manager");
|
2073
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1819
2074
|
if (permissionChecker2.cannot.delete()) {
|
1820
2075
|
return ctx.forbidden();
|
1821
2076
|
}
|
1822
2077
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1823
|
-
const populate = await getService$
|
1824
|
-
const { locale } = await getDocumentLocaleAndStatus(ctx.query);
|
2078
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2079
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1825
2080
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1826
2081
|
if (documentLocales.length === 0) {
|
1827
2082
|
return ctx.notFound();
|
@@ -1842,19 +2097,42 @@ const collectionTypes = {
|
|
1842
2097
|
const { userAbility } = ctx.state;
|
1843
2098
|
const { id, model } = ctx.params;
|
1844
2099
|
const { body } = ctx.request;
|
1845
|
-
const documentManager2 = getService$
|
1846
|
-
const permissionChecker2 = getService$
|
2100
|
+
const documentManager2 = getService$2("document-manager");
|
2101
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1847
2102
|
if (permissionChecker2.cannot.publish()) {
|
1848
2103
|
return ctx.forbidden();
|
1849
2104
|
}
|
1850
2105
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1851
2106
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1852
|
-
const populate = await getService$
|
1853
|
-
|
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
|
+
}
|
1854
2133
|
if (permissionChecker2.cannot.publish(document)) {
|
1855
2134
|
throw new errors.ForbiddenError();
|
1856
2135
|
}
|
1857
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1858
2136
|
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1859
2137
|
locale
|
1860
2138
|
// TODO: Allow setting creator fields on publish
|
@@ -1874,14 +2152,16 @@ const collectionTypes = {
|
|
1874
2152
|
const { body } = ctx.request;
|
1875
2153
|
const { documentIds } = body;
|
1876
2154
|
await validateBulkActionInput(body);
|
1877
|
-
const documentManager2 = getService$
|
1878
|
-
const permissionChecker2 = getService$
|
2155
|
+
const documentManager2 = getService$2("document-manager");
|
2156
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1879
2157
|
if (permissionChecker2.cannot.publish()) {
|
1880
2158
|
return ctx.forbidden();
|
1881
2159
|
}
|
1882
2160
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1883
|
-
const populate = await getService$
|
1884
|
-
const { locale } = await getDocumentLocaleAndStatus(body, {
|
2161
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
2162
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2163
|
+
allowMultipleLocales: true
|
2164
|
+
});
|
1885
2165
|
const entityPromises = documentIds.map(
|
1886
2166
|
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1887
2167
|
);
|
@@ -1903,12 +2183,14 @@ const collectionTypes = {
|
|
1903
2183
|
const { body } = ctx.request;
|
1904
2184
|
const { documentIds } = body;
|
1905
2185
|
await validateBulkActionInput(body);
|
1906
|
-
const documentManager2 = getService$
|
1907
|
-
const permissionChecker2 = getService$
|
2186
|
+
const documentManager2 = getService$2("document-manager");
|
2187
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1908
2188
|
if (permissionChecker2.cannot.unpublish()) {
|
1909
2189
|
return ctx.forbidden();
|
1910
2190
|
}
|
1911
|
-
const { locale } = await getDocumentLocaleAndStatus(body
|
2191
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2192
|
+
allowMultipleLocales: true
|
2193
|
+
});
|
1912
2194
|
const entityPromises = documentIds.map(
|
1913
2195
|
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1914
2196
|
);
|
@@ -1931,8 +2213,8 @@ const collectionTypes = {
|
|
1931
2213
|
const {
|
1932
2214
|
body: { discardDraft, ...body }
|
1933
2215
|
} = ctx.request;
|
1934
|
-
const documentManager2 = getService$
|
1935
|
-
const permissionChecker2 = getService$
|
2216
|
+
const documentManager2 = getService$2("document-manager");
|
2217
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1936
2218
|
if (permissionChecker2.cannot.unpublish()) {
|
1937
2219
|
return ctx.forbidden();
|
1938
2220
|
}
|
@@ -1940,8 +2222,8 @@ const collectionTypes = {
|
|
1940
2222
|
return ctx.forbidden();
|
1941
2223
|
}
|
1942
2224
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1943
|
-
const populate = await getService$
|
1944
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2225
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2226
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1945
2227
|
const document = await documentManager2.findOne(id, model, {
|
1946
2228
|
populate,
|
1947
2229
|
locale,
|
@@ -1971,14 +2253,14 @@ const collectionTypes = {
|
|
1971
2253
|
const { userAbility } = ctx.state;
|
1972
2254
|
const { id, model } = ctx.params;
|
1973
2255
|
const { body } = ctx.request;
|
1974
|
-
const documentManager2 = getService$
|
1975
|
-
const permissionChecker2 = getService$
|
2256
|
+
const documentManager2 = getService$2("document-manager");
|
2257
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
1976
2258
|
if (permissionChecker2.cannot.discard()) {
|
1977
2259
|
return ctx.forbidden();
|
1978
2260
|
}
|
1979
2261
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1980
|
-
const populate = await getService$
|
1981
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2262
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2263
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1982
2264
|
const document = await documentManager2.findOne(id, model, {
|
1983
2265
|
populate,
|
1984
2266
|
locale,
|
@@ -2002,14 +2284,14 @@ const collectionTypes = {
|
|
2002
2284
|
const { query, body } = ctx.request;
|
2003
2285
|
const { documentIds } = body;
|
2004
2286
|
await validateBulkActionInput(body);
|
2005
|
-
const documentManager2 = getService$
|
2006
|
-
const permissionChecker2 = getService$
|
2287
|
+
const documentManager2 = getService$2("document-manager");
|
2288
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2007
2289
|
if (permissionChecker2.cannot.delete()) {
|
2008
2290
|
return ctx.forbidden();
|
2009
2291
|
}
|
2010
2292
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2011
|
-
const populate = await getService$
|
2012
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2293
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2294
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2013
2295
|
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2014
2296
|
populate,
|
2015
2297
|
locale
|
@@ -2029,14 +2311,14 @@ const collectionTypes = {
|
|
2029
2311
|
async countDraftRelations(ctx) {
|
2030
2312
|
const { userAbility } = ctx.state;
|
2031
2313
|
const { model, id } = ctx.params;
|
2032
|
-
const documentManager2 = getService$
|
2033
|
-
const permissionChecker2 = getService$
|
2314
|
+
const documentManager2 = getService$2("document-manager");
|
2315
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2034
2316
|
if (permissionChecker2.cannot.read()) {
|
2035
2317
|
return ctx.forbidden();
|
2036
2318
|
}
|
2037
2319
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2038
|
-
const populate = await getService$
|
2039
|
-
const { locale, status
|
2320
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2321
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
2040
2322
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
2041
2323
|
if (!entity) {
|
2042
2324
|
return ctx.notFound();
|
@@ -2054,12 +2336,12 @@ const collectionTypes = {
|
|
2054
2336
|
const ids = ctx.request.query.documentIds;
|
2055
2337
|
const locale = ctx.request.query.locale;
|
2056
2338
|
const { model } = ctx.params;
|
2057
|
-
const documentManager2 = getService$
|
2058
|
-
const permissionChecker2 = getService$
|
2339
|
+
const documentManager2 = getService$2("document-manager");
|
2340
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2059
2341
|
if (permissionChecker2.cannot.read()) {
|
2060
2342
|
return ctx.forbidden();
|
2061
2343
|
}
|
2062
|
-
const
|
2344
|
+
const documents = await documentManager2.findMany(
|
2063
2345
|
{
|
2064
2346
|
filters: {
|
2065
2347
|
documentId: ids
|
@@ -2068,7 +2350,7 @@ const collectionTypes = {
|
|
2068
2350
|
},
|
2069
2351
|
model
|
2070
2352
|
);
|
2071
|
-
if (!
|
2353
|
+
if (!documents) {
|
2072
2354
|
return ctx.notFound();
|
2073
2355
|
}
|
2074
2356
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2079,13 +2361,13 @@ const collectionTypes = {
|
|
2079
2361
|
};
|
2080
2362
|
const components$1 = {
|
2081
2363
|
findComponents(ctx) {
|
2082
|
-
const components2 = getService$
|
2083
|
-
const { toDto } = getService$
|
2364
|
+
const components2 = getService$2("components").findAllComponents();
|
2365
|
+
const { toDto } = getService$2("data-mapper");
|
2084
2366
|
ctx.body = { data: components2.map(toDto) };
|
2085
2367
|
},
|
2086
2368
|
async findComponentConfiguration(ctx) {
|
2087
2369
|
const { uid: uid2 } = ctx.params;
|
2088
|
-
const componentService = getService$
|
2370
|
+
const componentService = getService$2("components");
|
2089
2371
|
const component = componentService.findComponent(uid2);
|
2090
2372
|
if (!component) {
|
2091
2373
|
return ctx.notFound("component.notFound");
|
@@ -2102,7 +2384,7 @@ const components$1 = {
|
|
2102
2384
|
async updateComponentConfiguration(ctx) {
|
2103
2385
|
const { uid: uid2 } = ctx.params;
|
2104
2386
|
const { body } = ctx.request;
|
2105
|
-
const componentService = getService$
|
2387
|
+
const componentService = getService$2("components");
|
2106
2388
|
const component = componentService.findComponent(uid2);
|
2107
2389
|
if (!component) {
|
2108
2390
|
return ctx.notFound("component.notFound");
|
@@ -2136,12 +2418,12 @@ const contentTypes = {
|
|
2136
2418
|
} catch (error) {
|
2137
2419
|
return ctx.send({ error }, 400);
|
2138
2420
|
}
|
2139
|
-
const contentTypes2 = getService$
|
2140
|
-
const { toDto } = getService$
|
2421
|
+
const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
|
2422
|
+
const { toDto } = getService$2("data-mapper");
|
2141
2423
|
ctx.body = { data: contentTypes2.map(toDto) };
|
2142
2424
|
},
|
2143
2425
|
async findContentTypesSettings(ctx) {
|
2144
|
-
const { findAllContentTypes, findConfiguration } = getService$
|
2426
|
+
const { findAllContentTypes, findConfiguration } = getService$2("content-types");
|
2145
2427
|
const contentTypes2 = await findAllContentTypes();
|
2146
2428
|
const configurations = await Promise.all(
|
2147
2429
|
contentTypes2.map(async (contentType) => {
|
@@ -2155,7 +2437,7 @@ const contentTypes = {
|
|
2155
2437
|
},
|
2156
2438
|
async findContentTypeConfiguration(ctx) {
|
2157
2439
|
const { uid: uid2 } = ctx.params;
|
2158
|
-
const contentTypeService = getService$
|
2440
|
+
const contentTypeService = getService$2("content-types");
|
2159
2441
|
const contentType = await contentTypeService.findContentType(uid2);
|
2160
2442
|
if (!contentType) {
|
2161
2443
|
return ctx.notFound("contentType.notFound");
|
@@ -2177,13 +2459,13 @@ const contentTypes = {
|
|
2177
2459
|
const { userAbility } = ctx.state;
|
2178
2460
|
const { uid: uid2 } = ctx.params;
|
2179
2461
|
const { body } = ctx.request;
|
2180
|
-
const contentTypeService = getService$
|
2181
|
-
const metricsService = getService$
|
2462
|
+
const contentTypeService = getService$2("content-types");
|
2463
|
+
const metricsService = getService$2("metrics");
|
2182
2464
|
const contentType = await contentTypeService.findContentType(uid2);
|
2183
2465
|
if (!contentType) {
|
2184
2466
|
return ctx.notFound("contentType.notFound");
|
2185
2467
|
}
|
2186
|
-
if (!getService$
|
2468
|
+
if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
|
2187
2469
|
return ctx.forbidden();
|
2188
2470
|
}
|
2189
2471
|
let input;
|
@@ -2216,10 +2498,10 @@ const contentTypes = {
|
|
2216
2498
|
};
|
2217
2499
|
const init = {
|
2218
2500
|
getInitData(ctx) {
|
2219
|
-
const { toDto } = getService$
|
2220
|
-
const { findAllComponents } = getService$
|
2221
|
-
const { getAllFieldSizes } = getService$
|
2222
|
-
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");
|
2223
2505
|
ctx.body = {
|
2224
2506
|
data: {
|
2225
2507
|
fieldSizes: getAllFieldSizes(),
|
@@ -2255,36 +2537,41 @@ const addFiltersClause = (params, filtersClause) => {
|
|
2255
2537
|
params.filters.$and.push(filtersClause);
|
2256
2538
|
};
|
2257
2539
|
const sanitizeMainField = (model, mainField, userAbility) => {
|
2258
|
-
const permissionChecker2 = getService$
|
2540
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2259
2541
|
userAbility,
|
2260
2542
|
model: model.uid
|
2261
2543
|
});
|
2262
|
-
|
2544
|
+
const isMainFieldListable = isListable(model, mainField);
|
2545
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2546
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2263
2547
|
return "id";
|
2264
2548
|
}
|
2265
|
-
if (
|
2266
|
-
|
2267
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2268
|
-
userAbility,
|
2269
|
-
model: "plugin::users-permissions.user"
|
2270
|
-
});
|
2271
|
-
if (userPermissionChecker.can.read()) {
|
2272
|
-
return "name";
|
2273
|
-
}
|
2274
|
-
}
|
2275
|
-
return "id";
|
2549
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2550
|
+
return "name";
|
2276
2551
|
}
|
2277
2552
|
return mainField;
|
2278
2553
|
};
|
2279
|
-
const addStatusToRelations = async (
|
2280
|
-
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) {
|
2281
2560
|
return relations2;
|
2282
2561
|
}
|
2283
|
-
const
|
2284
|
-
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
|
+
});
|
2285
2572
|
return relations2.map((relation) => {
|
2286
|
-
const availableStatuses =
|
2287
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2573
|
+
const availableStatuses = availableStatus.filter(
|
2574
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2288
2575
|
);
|
2289
2576
|
return {
|
2290
2577
|
...relation,
|
@@ -2305,11 +2592,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2305
2592
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2306
2593
|
const isSourceLocalized = isLocalized(sourceModel);
|
2307
2594
|
const isTargetLocalized = isLocalized(targetModel);
|
2308
|
-
let validatedLocale = locale;
|
2309
|
-
if (!targetModel || !isTargetLocalized)
|
2310
|
-
validatedLocale = void 0;
|
2311
2595
|
return {
|
2312
|
-
locale
|
2596
|
+
locale,
|
2313
2597
|
isSourceLocalized,
|
2314
2598
|
isTargetLocalized
|
2315
2599
|
};
|
@@ -2318,8 +2602,7 @@ const validateStatus = (sourceUid, status) => {
|
|
2318
2602
|
const sourceModel = strapi.getModel(sourceUid);
|
2319
2603
|
const isDP = contentTypes$1.hasDraftAndPublish;
|
2320
2604
|
const isSourceDP = isDP(sourceModel);
|
2321
|
-
if (!isSourceDP)
|
2322
|
-
return { status: void 0 };
|
2605
|
+
if (!isSourceDP) return { status: void 0 };
|
2323
2606
|
switch (status) {
|
2324
2607
|
case "published":
|
2325
2608
|
return { status: "published" };
|
@@ -2349,7 +2632,7 @@ const relations = {
|
|
2349
2632
|
ctx.request?.query?.locale
|
2350
2633
|
);
|
2351
2634
|
const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
|
2352
|
-
const permissionChecker2 = getService$
|
2635
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2353
2636
|
userAbility,
|
2354
2637
|
model
|
2355
2638
|
});
|
@@ -2374,7 +2657,7 @@ const relations = {
|
|
2374
2657
|
where.id = id;
|
2375
2658
|
}
|
2376
2659
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2377
|
-
const populate = await getService$
|
2660
|
+
const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2378
2661
|
const currentEntity = await strapi.db.query(model).findOne({
|
2379
2662
|
where,
|
2380
2663
|
populate
|
@@ -2389,7 +2672,7 @@ const relations = {
|
|
2389
2672
|
}
|
2390
2673
|
entryId = currentEntity.id;
|
2391
2674
|
}
|
2392
|
-
const modelConfig = isComponent2 ? await getService$
|
2675
|
+
const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
|
2393
2676
|
const targetSchema = strapi.getModel(targetUid);
|
2394
2677
|
const mainField = flow(
|
2395
2678
|
prop(`metadatas.${targetField}.edit.mainField`),
|
@@ -2412,7 +2695,7 @@ const relations = {
|
|
2412
2695
|
attribute,
|
2413
2696
|
fieldsToSelect,
|
2414
2697
|
mainField,
|
2415
|
-
source: { schema: sourceSchema },
|
2698
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2416
2699
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2417
2700
|
sourceSchema,
|
2418
2701
|
targetSchema,
|
@@ -2434,7 +2717,8 @@ const relations = {
|
|
2434
2717
|
fieldsToSelect,
|
2435
2718
|
mainField,
|
2436
2719
|
source: {
|
2437
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2720
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2721
|
+
isLocalized: isSourceLocalized
|
2438
2722
|
},
|
2439
2723
|
target: {
|
2440
2724
|
schema: { uid: targetUid },
|
@@ -2442,7 +2726,7 @@ const relations = {
|
|
2442
2726
|
}
|
2443
2727
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2444
2728
|
const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
2445
|
-
const permissionChecker2 = getService$
|
2729
|
+
const permissionChecker2 = getService$2("permission-checker").create({
|
2446
2730
|
userAbility: ctx.state.userAbility,
|
2447
2731
|
model: targetUid
|
2448
2732
|
});
|
@@ -2472,12 +2756,16 @@ const relations = {
|
|
2472
2756
|
} else {
|
2473
2757
|
where.id = id;
|
2474
2758
|
}
|
2475
|
-
|
2476
|
-
|
2759
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2760
|
+
if (!isEmpty(publishedAt)) {
|
2761
|
+
where[`${alias}.published_at`] = publishedAt;
|
2477
2762
|
}
|
2478
|
-
if (
|
2763
|
+
if (isTargetLocalized && locale) {
|
2479
2764
|
where[`${alias}.locale`] = locale;
|
2480
2765
|
}
|
2766
|
+
if (isSourceLocalized && locale) {
|
2767
|
+
where.locale = locale;
|
2768
|
+
}
|
2481
2769
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2482
2770
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2483
2771
|
}
|
@@ -2495,7 +2783,8 @@ const relations = {
|
|
2495
2783
|
id: { $notIn: uniq(idsToOmit) }
|
2496
2784
|
});
|
2497
2785
|
}
|
2498
|
-
const
|
2786
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2787
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2499
2788
|
ctx.body = {
|
2500
2789
|
...res,
|
2501
2790
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2510,29 +2799,39 @@ const relations = {
|
|
2510
2799
|
attribute,
|
2511
2800
|
targetField,
|
2512
2801
|
fieldsToSelect,
|
2513
|
-
|
2514
|
-
|
2515
|
-
}
|
2516
|
-
target: {
|
2517
|
-
schema: { uid: targetUid }
|
2518
|
-
}
|
2802
|
+
status,
|
2803
|
+
source: { schema: sourceSchema },
|
2804
|
+
target: { schema: targetSchema }
|
2519
2805
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2520
|
-
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 });
|
2521
2809
|
const dbQuery = strapi.db.query(sourceUid);
|
2522
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
|
+
}
|
2523
2823
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2524
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2824
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2525
2825
|
ordering: "desc",
|
2526
2826
|
page: ctx.request.query.page,
|
2527
|
-
pageSize: ctx.request.query.pageSize
|
2827
|
+
pageSize: ctx.request.query.pageSize,
|
2828
|
+
filters
|
2528
2829
|
});
|
2529
2830
|
const loadedIds = res.results.map((item) => item.id);
|
2530
2831
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2531
2832
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2532
2833
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2533
|
-
ordering: "desc"
|
2534
|
-
page: ctx.request.query.page,
|
2535
|
-
pageSize: ctx.request.query.pageSize
|
2834
|
+
ordering: "desc"
|
2536
2835
|
});
|
2537
2836
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2538
2837
|
ctx.body = {
|
@@ -2547,10 +2846,10 @@ const relations = {
|
|
2547
2846
|
}
|
2548
2847
|
};
|
2549
2848
|
const buildPopulateFromQuery = async (query, model) => {
|
2550
|
-
return getService$
|
2849
|
+
return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
|
2551
2850
|
};
|
2552
2851
|
const findDocument = async (query, uid2, opts = {}) => {
|
2553
|
-
const documentManager2 = getService$
|
2852
|
+
const documentManager2 = getService$2("document-manager");
|
2554
2853
|
const populate = await buildPopulateFromQuery(query, uid2);
|
2555
2854
|
return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
|
2556
2855
|
};
|
@@ -2558,13 +2857,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2558
2857
|
const { user, userAbility } = ctx.state;
|
2559
2858
|
const { model } = ctx.params;
|
2560
2859
|
const { body, query } = ctx.request;
|
2561
|
-
const documentManager2 = getService$
|
2562
|
-
const permissionChecker2 = getService$
|
2860
|
+
const documentManager2 = getService$2("document-manager");
|
2861
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2563
2862
|
if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
|
2564
2863
|
throw new errors.ForbiddenError();
|
2565
2864
|
}
|
2566
2865
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2567
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2866
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2568
2867
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2569
2868
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2570
2869
|
// Find the first document to check if it exists
|
@@ -2600,12 +2899,12 @@ const singleTypes = {
|
|
2600
2899
|
const { userAbility } = ctx.state;
|
2601
2900
|
const { model } = ctx.params;
|
2602
2901
|
const { query = {} } = ctx.request;
|
2603
|
-
const permissionChecker2 = getService$
|
2902
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2604
2903
|
if (permissionChecker2.cannot.read()) {
|
2605
2904
|
return ctx.forbidden();
|
2606
2905
|
}
|
2607
2906
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2608
|
-
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
2907
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2609
2908
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2610
2909
|
if (!version) {
|
2611
2910
|
if (permissionChecker2.cannot.create()) {
|
@@ -2619,7 +2918,7 @@ const singleTypes = {
|
|
2619
2918
|
permissionChecker2,
|
2620
2919
|
model,
|
2621
2920
|
// @ts-expect-error - fix types
|
2622
|
-
{
|
2921
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2623
2922
|
{ availableLocales: true, availableStatus: false }
|
2624
2923
|
);
|
2625
2924
|
ctx.body = { data: {}, meta };
|
@@ -2634,7 +2933,7 @@ const singleTypes = {
|
|
2634
2933
|
async createOrUpdate(ctx) {
|
2635
2934
|
const { userAbility } = ctx.state;
|
2636
2935
|
const { model } = ctx.params;
|
2637
|
-
const permissionChecker2 = getService$
|
2936
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2638
2937
|
const document = await createOrUpdateDocument(ctx);
|
2639
2938
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2640
2939
|
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
@@ -2643,14 +2942,14 @@ const singleTypes = {
|
|
2643
2942
|
const { userAbility } = ctx.state;
|
2644
2943
|
const { model } = ctx.params;
|
2645
2944
|
const { query = {} } = ctx.request;
|
2646
|
-
const documentManager2 = getService$
|
2647
|
-
const permissionChecker2 = getService$
|
2945
|
+
const documentManager2 = getService$2("document-manager");
|
2946
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2648
2947
|
if (permissionChecker2.cannot.delete()) {
|
2649
2948
|
return ctx.forbidden();
|
2650
2949
|
}
|
2651
2950
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2652
2951
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2653
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
2952
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2654
2953
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2655
2954
|
populate,
|
2656
2955
|
locale
|
@@ -2672,8 +2971,8 @@ const singleTypes = {
|
|
2672
2971
|
const { userAbility } = ctx.state;
|
2673
2972
|
const { model } = ctx.params;
|
2674
2973
|
const { query = {} } = ctx.request;
|
2675
|
-
const documentManager2 = getService$
|
2676
|
-
const permissionChecker2 = getService$
|
2974
|
+
const documentManager2 = getService$2("document-manager");
|
2975
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2677
2976
|
if (permissionChecker2.cannot.publish()) {
|
2678
2977
|
return ctx.forbidden();
|
2679
2978
|
}
|
@@ -2687,7 +2986,7 @@ const singleTypes = {
|
|
2687
2986
|
if (permissionChecker2.cannot.publish(document)) {
|
2688
2987
|
throw new errors.ForbiddenError();
|
2689
2988
|
}
|
2690
|
-
const { locale } = await getDocumentLocaleAndStatus(document);
|
2989
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2691
2990
|
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2692
2991
|
return publishResult.at(0);
|
2693
2992
|
});
|
@@ -2701,8 +3000,8 @@ const singleTypes = {
|
|
2701
3000
|
body: { discardDraft, ...body },
|
2702
3001
|
query = {}
|
2703
3002
|
} = ctx.request;
|
2704
|
-
const documentManager2 = getService$
|
2705
|
-
const permissionChecker2 = getService$
|
3003
|
+
const documentManager2 = getService$2("document-manager");
|
3004
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2706
3005
|
if (permissionChecker2.cannot.unpublish()) {
|
2707
3006
|
return ctx.forbidden();
|
2708
3007
|
}
|
@@ -2710,7 +3009,7 @@ const singleTypes = {
|
|
2710
3009
|
return ctx.forbidden();
|
2711
3010
|
}
|
2712
3011
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2713
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
3012
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2714
3013
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2715
3014
|
if (!document) {
|
2716
3015
|
return ctx.notFound();
|
@@ -2736,13 +3035,13 @@ const singleTypes = {
|
|
2736
3035
|
const { userAbility } = ctx.state;
|
2737
3036
|
const { model } = ctx.params;
|
2738
3037
|
const { body, query = {} } = ctx.request;
|
2739
|
-
const documentManager2 = getService$
|
2740
|
-
const permissionChecker2 = getService$
|
3038
|
+
const documentManager2 = getService$2("document-manager");
|
3039
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
2741
3040
|
if (permissionChecker2.cannot.discard()) {
|
2742
3041
|
return ctx.forbidden();
|
2743
3042
|
}
|
2744
3043
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2745
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
3044
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2746
3045
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2747
3046
|
if (!document) {
|
2748
3047
|
return ctx.notFound();
|
@@ -2760,9 +3059,9 @@ const singleTypes = {
|
|
2760
3059
|
const { userAbility } = ctx.state;
|
2761
3060
|
const { model } = ctx.params;
|
2762
3061
|
const { query } = ctx.request;
|
2763
|
-
const documentManager2 = getService$
|
2764
|
-
const permissionChecker2 = getService$
|
2765
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
3062
|
+
const documentManager2 = getService$2("document-manager");
|
3063
|
+
const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
|
3064
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2766
3065
|
if (permissionChecker2.cannot.read()) {
|
2767
3066
|
return ctx.forbidden();
|
2768
3067
|
}
|
@@ -2783,9 +3082,9 @@ const uid$1 = {
|
|
2783
3082
|
async generateUID(ctx) {
|
2784
3083
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2785
3084
|
const { query = {} } = ctx.request;
|
2786
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
3085
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2787
3086
|
await validateUIDField(contentTypeUID, field);
|
2788
|
-
const uidService = getService$
|
3087
|
+
const uidService = getService$2("uid");
|
2789
3088
|
ctx.body = {
|
2790
3089
|
data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
|
2791
3090
|
};
|
@@ -2795,9 +3094,9 @@ const uid$1 = {
|
|
2795
3094
|
ctx.request.body
|
2796
3095
|
);
|
2797
3096
|
const { query = {} } = ctx.request;
|
2798
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
3097
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2799
3098
|
await validateUIDField(contentTypeUID, field);
|
2800
|
-
const uidService = getService$
|
3099
|
+
const uidService = getService$2("uid");
|
2801
3100
|
const isAvailable = await uidService.checkUIDAvailability({
|
2802
3101
|
contentTypeUID,
|
2803
3102
|
field,
|
@@ -2818,7 +3117,8 @@ const controllers = {
|
|
2818
3117
|
relations,
|
2819
3118
|
"single-types": singleTypes,
|
2820
3119
|
uid: uid$1,
|
2821
|
-
...history.controllers ? history.controllers : {}
|
3120
|
+
...history.controllers ? history.controllers : {},
|
3121
|
+
...preview.controllers ? preview.controllers : {}
|
2822
3122
|
};
|
2823
3123
|
const keys = {
|
2824
3124
|
CONFIGURATION: "configuration"
|
@@ -2947,18 +3247,15 @@ async function syncMetadatas(configuration, schema) {
|
|
2947
3247
|
_.set(updatedMeta, ["list", "searchable"], false);
|
2948
3248
|
_.set(acc, [key], updatedMeta);
|
2949
3249
|
}
|
2950
|
-
if (!_.has(edit, "mainField"))
|
2951
|
-
return acc;
|
3250
|
+
if (!_.has(edit, "mainField")) return acc;
|
2952
3251
|
if (!isRelation$1(attr)) {
|
2953
3252
|
_.set(updatedMeta, "edit", _.omit(edit, ["mainField"]));
|
2954
3253
|
_.set(acc, [key], updatedMeta);
|
2955
3254
|
return acc;
|
2956
3255
|
}
|
2957
|
-
if (edit.mainField === "id")
|
2958
|
-
return acc;
|
3256
|
+
if (edit.mainField === "id") return acc;
|
2959
3257
|
const targetSchema = getTargetSchema(attr.targetModel);
|
2960
|
-
if (!targetSchema)
|
2961
|
-
return acc;
|
3258
|
+
if (!targetSchema) return acc;
|
2962
3259
|
if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
|
2963
3260
|
_.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
|
2964
3261
|
_.set(acc, [key], updatedMeta);
|
@@ -2969,12 +3266,12 @@ async function syncMetadatas(configuration, schema) {
|
|
2969
3266
|
return _.assign(metasWithDefaults, updatedMetas);
|
2970
3267
|
}
|
2971
3268
|
const getTargetSchema = (targetModel) => {
|
2972
|
-
return getService$
|
3269
|
+
return getService$2("content-types").findContentType(targetModel);
|
2973
3270
|
};
|
2974
3271
|
const DEFAULT_LIST_LENGTH = 4;
|
2975
3272
|
const MAX_ROW_SIZE = 12;
|
2976
3273
|
const isAllowedFieldSize = (type, size) => {
|
2977
|
-
const { getFieldSize } = getService$
|
3274
|
+
const { getFieldSize } = getService$2("field-sizes");
|
2978
3275
|
const fieldSize = getFieldSize(type);
|
2979
3276
|
if (!fieldSize.isResizable && size !== fieldSize.default) {
|
2980
3277
|
return false;
|
@@ -2982,7 +3279,7 @@ const isAllowedFieldSize = (type, size) => {
|
|
2982
3279
|
return size <= MAX_ROW_SIZE;
|
2983
3280
|
};
|
2984
3281
|
const getDefaultFieldSize = (attribute) => {
|
2985
|
-
const { hasFieldSize, getFieldSize } = getService$
|
3282
|
+
const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
|
2986
3283
|
return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
|
2987
3284
|
};
|
2988
3285
|
async function createDefaultLayouts(schema) {
|
@@ -3003,8 +3300,7 @@ function createDefaultEditLayout(schema) {
|
|
3003
3300
|
return appendToEditLayout([], keys2, schema);
|
3004
3301
|
}
|
3005
3302
|
function syncLayouts(configuration, schema) {
|
3006
|
-
if (_.isEmpty(configuration.layouts))
|
3007
|
-
return createDefaultLayouts(schema);
|
3303
|
+
if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
|
3008
3304
|
const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
|
3009
3305
|
let cleanList = list.filter((attr) => isListable(schema, attr));
|
3010
3306
|
const cleanEditRelations = editRelations.filter(
|
@@ -3015,9 +3311,8 @@ function syncLayouts(configuration, schema) {
|
|
3015
3311
|
for (const row of edit) {
|
3016
3312
|
const newRow = [];
|
3017
3313
|
for (const el of row) {
|
3018
|
-
if (!hasEditableAttribute(schema, el.name))
|
3019
|
-
|
3020
|
-
const { hasFieldSize } = getService$1("field-sizes");
|
3314
|
+
if (!hasEditableAttribute(schema, el.name)) continue;
|
3315
|
+
const { hasFieldSize } = getService$2("field-sizes");
|
3021
3316
|
const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
|
3022
3317
|
if (!isAllowedFieldSize(fieldType, el.size)) {
|
3023
3318
|
elementsToReAppend.push(el.name);
|
@@ -3047,8 +3342,7 @@ function syncLayouts(configuration, schema) {
|
|
3047
3342
|
};
|
3048
3343
|
}
|
3049
3344
|
const appendToEditLayout = (layout = [], keysToAppend, schema) => {
|
3050
|
-
if (keysToAppend.length === 0)
|
3051
|
-
return layout;
|
3345
|
+
if (keysToAppend.length === 0) return layout;
|
3052
3346
|
let currentRowIndex = Math.max(layout.length - 1, 0);
|
3053
3347
|
if (!layout[currentRowIndex]) {
|
3054
3348
|
layout[currentRowIndex] = [];
|
@@ -3157,17 +3451,17 @@ const configurationService$1 = createConfigurationService({
|
|
3157
3451
|
isComponent: true,
|
3158
3452
|
prefix: STORE_KEY_PREFIX,
|
3159
3453
|
getModels() {
|
3160
|
-
const { toContentManagerModel } = getService$
|
3454
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3161
3455
|
return mapValues(toContentManagerModel, strapi.components);
|
3162
3456
|
}
|
3163
3457
|
});
|
3164
3458
|
const components = ({ strapi: strapi2 }) => ({
|
3165
3459
|
findAllComponents() {
|
3166
|
-
const { toContentManagerModel } = getService$
|
3460
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3167
3461
|
return Object.values(strapi2.components).map(toContentManagerModel);
|
3168
3462
|
},
|
3169
3463
|
findComponent(uid2) {
|
3170
|
-
const { toContentManagerModel } = getService$
|
3464
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3171
3465
|
const component = strapi2.components[uid2];
|
3172
3466
|
return isNil$1(component) ? component : toContentManagerModel(component);
|
3173
3467
|
},
|
@@ -3218,17 +3512,17 @@ const configurationService = createConfigurationService({
|
|
3218
3512
|
storeUtils,
|
3219
3513
|
prefix: "content_types",
|
3220
3514
|
getModels() {
|
3221
|
-
const { toContentManagerModel } = getService$
|
3515
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3222
3516
|
return mapValues(toContentManagerModel, strapi.contentTypes);
|
3223
3517
|
}
|
3224
3518
|
});
|
3225
3519
|
const service = ({ strapi: strapi2 }) => ({
|
3226
3520
|
findAllContentTypes() {
|
3227
|
-
const { toContentManagerModel } = getService$
|
3521
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3228
3522
|
return Object.values(strapi2.contentTypes).map(toContentManagerModel);
|
3229
3523
|
},
|
3230
3524
|
findContentType(uid2) {
|
3231
|
-
const { toContentManagerModel } = getService$
|
3525
|
+
const { toContentManagerModel } = getService$2("data-mapper");
|
3232
3526
|
const contentType = strapi2.contentTypes[uid2];
|
3233
3527
|
return isNil$1(contentType) ? contentType : toContentManagerModel(contentType);
|
3234
3528
|
},
|
@@ -3257,7 +3551,7 @@ const service = ({ strapi: strapi2 }) => ({
|
|
3257
3551
|
return this.findConfiguration(contentType);
|
3258
3552
|
},
|
3259
3553
|
findComponentsConfigurations(contentType) {
|
3260
|
-
return getService$
|
3554
|
+
return getService$2("components").findComponentsConfigurations(contentType);
|
3261
3555
|
},
|
3262
3556
|
syncConfigurations() {
|
3263
3557
|
return configurationService.syncConfigurations();
|
@@ -3438,12 +3732,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3438
3732
|
ability: userAbility,
|
3439
3733
|
model
|
3440
3734
|
});
|
3441
|
-
const
|
3735
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3736
|
+
const toSubject = (entity) => {
|
3737
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3738
|
+
};
|
3442
3739
|
const can = (action, entity, field) => {
|
3443
|
-
|
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
|
+
);
|
3444
3747
|
};
|
3445
3748
|
const cannot = (action, entity, field) => {
|
3446
|
-
|
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
|
+
);
|
3447
3756
|
};
|
3448
3757
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3449
3758
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3514,7 +3823,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3514
3823
|
return userAbility.can(action);
|
3515
3824
|
},
|
3516
3825
|
async registerPermissions() {
|
3517
|
-
const displayedContentTypes = getService$
|
3826
|
+
const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
|
3518
3827
|
const contentTypesUids = displayedContentTypes.map(prop("uid"));
|
3519
3828
|
const actions = [
|
3520
3829
|
{
|
@@ -3599,6 +3908,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
|
|
3599
3908
|
if (initialPopulate) {
|
3600
3909
|
return initialPopulate;
|
3601
3910
|
}
|
3911
|
+
if (attributeName === "localizations") {
|
3912
|
+
const validationPopulate = getPopulateForValidation(model.uid);
|
3913
|
+
return {
|
3914
|
+
populate: validationPopulate.populate
|
3915
|
+
};
|
3916
|
+
}
|
3602
3917
|
if (!isVisibleAttribute$1(model, attributeName)) {
|
3603
3918
|
return true;
|
3604
3919
|
}
|
@@ -3658,6 +3973,9 @@ const getDeepPopulate = (uid2, {
|
|
3658
3973
|
return {};
|
3659
3974
|
}
|
3660
3975
|
const model = strapi.getModel(uid2);
|
3976
|
+
if (!model) {
|
3977
|
+
return {};
|
3978
|
+
}
|
3661
3979
|
return Object.keys(model.attributes).reduce(
|
3662
3980
|
(populateAcc, attributeName) => merge(
|
3663
3981
|
populateAcc,
|
@@ -3677,40 +3995,46 @@ const getDeepPopulate = (uid2, {
|
|
3677
3995
|
{}
|
3678
3996
|
);
|
3679
3997
|
};
|
3680
|
-
const
|
3681
|
-
|
3682
|
-
|
3683
|
-
countOne = false,
|
3684
|
-
maxLevel = Infinity
|
3685
|
-
} = {}, level = 1) => {
|
3686
|
-
if (level > maxLevel) {
|
3998
|
+
const getPopulateForValidation = (uid2) => {
|
3999
|
+
const model = strapi.getModel(uid2);
|
4000
|
+
if (!model) {
|
3687
4001
|
return {};
|
3688
4002
|
}
|
3689
|
-
const model = strapi.getModel(uid2);
|
3690
4003
|
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3691
|
-
if (
|
4004
|
+
if (isScalarAttribute(attribute)) {
|
4005
|
+
if (getDoesAttributeRequireValidation(attribute)) {
|
4006
|
+
populateAcc.fields = populateAcc.fields || [];
|
4007
|
+
populateAcc.fields.push(attributeName);
|
4008
|
+
}
|
3692
4009
|
return populateAcc;
|
3693
4010
|
}
|
3694
|
-
if (
|
3695
|
-
|
3696
|
-
|
3697
|
-
|
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;
|
3698
4019
|
}
|
3699
|
-
|
3700
|
-
|
3701
|
-
|
3702
|
-
|
3703
|
-
|
3704
|
-
|
3705
|
-
|
3706
|
-
|
3707
|
-
|
3708
|
-
countOne,
|
3709
|
-
maxLevel
|
4020
|
+
if (isDynamicZone(attribute)) {
|
4021
|
+
const components2 = attribute.components;
|
4022
|
+
const componentsResult = (components2 || []).reduce(
|
4023
|
+
(acc, componentUID) => {
|
4024
|
+
const componentResult = getPopulateForValidation(componentUID);
|
4025
|
+
if (Object.keys(componentResult).length > 0) {
|
4026
|
+
acc[componentUID] = componentResult;
|
4027
|
+
}
|
4028
|
+
return acc;
|
3710
4029
|
},
|
3711
|
-
|
3712
|
-
)
|
3713
|
-
|
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;
|
3714
4038
|
}, {});
|
3715
4039
|
};
|
3716
4040
|
const getDeepPopulateDraftCount = (uid2) => {
|
@@ -3720,6 +4044,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3720
4044
|
const attribute = model.attributes[attributeName];
|
3721
4045
|
switch (attribute.type) {
|
3722
4046
|
case "relation": {
|
4047
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
4048
|
+
if (isMorphRelation) {
|
4049
|
+
break;
|
4050
|
+
}
|
3723
4051
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3724
4052
|
populateAcc[attributeName] = {
|
3725
4053
|
count: true,
|
@@ -3786,7 +4114,7 @@ const getQueryPopulate = async (uid2, query) => {
|
|
3786
4114
|
return populateQuery;
|
3787
4115
|
};
|
3788
4116
|
const buildDeepPopulate = (uid2) => {
|
3789
|
-
return getService$
|
4117
|
+
return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
|
3790
4118
|
};
|
3791
4119
|
const populateBuilder = (uid2) => {
|
3792
4120
|
let getInitialPopulate = async () => {
|
@@ -3948,7 +4276,6 @@ const AVAILABLE_LOCALES_FIELDS = [
|
|
3948
4276
|
"locale",
|
3949
4277
|
"updatedAt",
|
3950
4278
|
"createdAt",
|
3951
|
-
"status",
|
3952
4279
|
"publishedAt",
|
3953
4280
|
"documentId"
|
3954
4281
|
];
|
@@ -3969,34 +4296,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3969
4296
|
/**
|
3970
4297
|
* Returns available locales of a document for the current status
|
3971
4298
|
*/
|
3972
|
-
async getAvailableLocales(uid2, version, allVersions
|
4299
|
+
async getAvailableLocales(uid2, version, allVersions) {
|
3973
4300
|
const versionsByLocale = groupBy("locale", allVersions);
|
3974
|
-
|
4301
|
+
if (version.locale) {
|
4302
|
+
delete versionsByLocale[version.locale];
|
4303
|
+
}
|
3975
4304
|
const model = strapi2.getModel(uid2);
|
3976
|
-
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
3977
|
-
const traversalFunction = async (localeVersion) => traverseEntity(
|
3978
|
-
({ key }, { remove }) => {
|
3979
|
-
if (keysToKeep.includes(key)) {
|
3980
|
-
return;
|
3981
|
-
}
|
3982
|
-
remove(key);
|
3983
|
-
},
|
3984
|
-
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
3985
|
-
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
3986
|
-
localeVersion
|
3987
|
-
);
|
3988
4305
|
const mappingResult = await async.map(
|
3989
4306
|
Object.values(versionsByLocale),
|
3990
4307
|
async (localeVersions) => {
|
3991
|
-
const mappedLocaleVersions = await async.map(
|
3992
|
-
localeVersions,
|
3993
|
-
traversalFunction
|
3994
|
-
);
|
3995
4308
|
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
3996
|
-
return
|
4309
|
+
return localeVersions[0];
|
3997
4310
|
}
|
3998
|
-
const draftVersion =
|
3999
|
-
const otherVersions =
|
4311
|
+
const draftVersion = localeVersions.find((v) => v.publishedAt === null);
|
4312
|
+
const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
|
4000
4313
|
if (!draftVersion) {
|
4001
4314
|
return;
|
4002
4315
|
}
|
@@ -4018,8 +4331,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4018
4331
|
const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
|
4019
4332
|
return matchLocale && matchStatus;
|
4020
4333
|
});
|
4021
|
-
if (!availableStatus)
|
4022
|
-
return availableStatus;
|
4334
|
+
if (!availableStatus) return availableStatus;
|
4023
4335
|
return pick(AVAILABLE_STATUS_FIELDS, availableStatus);
|
4024
4336
|
},
|
4025
4337
|
/**
|
@@ -4029,18 +4341,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4029
4341
|
* @returns
|
4030
4342
|
*/
|
4031
4343
|
async getManyAvailableStatus(uid2, documents) {
|
4032
|
-
if (!documents.length)
|
4033
|
-
return [];
|
4344
|
+
if (!documents.length) return [];
|
4034
4345
|
const status = documents[0].publishedAt !== null ? "published" : "draft";
|
4035
|
-
const
|
4036
|
-
const
|
4037
|
-
|
4038
|
-
|
4039
|
-
|
4040
|
-
|
4041
|
-
|
4042
|
-
|
4043
|
-
|
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"]
|
4044
4357
|
});
|
4045
4358
|
},
|
4046
4359
|
getStatus(version, otherDocumentStatuses) {
|
@@ -4057,10 +4370,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4057
4370
|
} else if (otherVersion) {
|
4058
4371
|
draftVersion = otherVersion;
|
4059
4372
|
}
|
4060
|
-
if (!draftVersion)
|
4061
|
-
|
4062
|
-
if (!publishedVersion)
|
4063
|
-
return CONTENT_MANAGER_STATUS.DRAFT;
|
4373
|
+
if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
|
4374
|
+
if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
|
4064
4375
|
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4065
4376
|
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
4066
4377
|
},
|
@@ -4068,11 +4379,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4068
4379
|
// We could refactor this so the locales are only loaded when they're
|
4069
4380
|
// needed. e.g. in the bulk locale action modal.
|
4070
4381
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4071
|
-
const populate =
|
4072
|
-
const
|
4073
|
-
where: { documentId: version.documentId },
|
4382
|
+
const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
|
4383
|
+
const params = {
|
4074
4384
|
populate: {
|
4075
|
-
// Populate only fields that require validation for bulk locale actions
|
4076
4385
|
...populate,
|
4077
4386
|
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
4078
4387
|
createdBy: {
|
@@ -4081,9 +4390,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4081
4390
|
updatedBy: {
|
4082
4391
|
select: ["id", "firstname", "lastname", "email"]
|
4083
4392
|
}
|
4393
|
+
},
|
4394
|
+
fields: uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
|
4395
|
+
filters: {
|
4396
|
+
documentId: version.documentId
|
4084
4397
|
}
|
4085
|
-
}
|
4086
|
-
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) : [];
|
4087
4402
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
4088
4403
|
return {
|
4089
4404
|
availableLocales: availableLocalesResult,
|
@@ -4097,13 +4412,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4097
4412
|
*/
|
4098
4413
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
4099
4414
|
if (!document) {
|
4100
|
-
return
|
4415
|
+
return {
|
4416
|
+
data: document,
|
4417
|
+
meta: {
|
4418
|
+
availableLocales: [],
|
4419
|
+
availableStatus: []
|
4420
|
+
}
|
4421
|
+
};
|
4101
4422
|
}
|
4102
4423
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
4103
4424
|
if (!hasDraftAndPublish) {
|
4104
4425
|
opts.availableStatus = false;
|
4105
4426
|
}
|
4106
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
|
+
}
|
4107
4438
|
return {
|
4108
4439
|
data: {
|
4109
4440
|
...document,
|
@@ -4205,10 +4536,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4205
4536
|
async clone(id, body, uid2) {
|
4206
4537
|
const populate = await buildDeepPopulate(uid2);
|
4207
4538
|
const params = {
|
4208
|
-
data:
|
4209
|
-
...omitIdField(body),
|
4210
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4211
|
-
},
|
4539
|
+
data: omitIdField(body),
|
4212
4540
|
populate
|
4213
4541
|
};
|
4214
4542
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4324,7 +4652,8 @@ const services = {
|
|
4324
4652
|
permission,
|
4325
4653
|
"populate-builder": populateBuilder$1,
|
4326
4654
|
uid,
|
4327
|
-
...history.services ? history.services : {}
|
4655
|
+
...history.services ? history.services : {},
|
4656
|
+
...preview.services ? preview.services : {}
|
4328
4657
|
};
|
4329
4658
|
const index = () => {
|
4330
4659
|
return {
|