@strapi/content-manager 0.0.0-experimental.a65a85fdea97faae8679d3ffc5f9d79af61abd26 → 0.0.0-experimental.bd712ad3930045f4a5d2144c119e0b7856e97fc4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
- package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
- package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-BWQv6yRj.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-BWQv6yRj.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs → ComponentConfigurationPage-C7ImeKGM.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-C7ImeKGM.mjs.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
- package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
- package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
- package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js → EditConfigurationPage-CEGwxV-L.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-CEGwxV-L.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs → EditConfigurationPage-MItFGzT9.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-MItFGzT9.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-CmMi2Xsn.js} +46 -48
- package/dist/_chunks/EditViewPage-CmMi2Xsn.js.map +1 -0
- package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs → EditViewPage-DhmAg0NK.mjs} +47 -47
- package/dist/_chunks/EditViewPage-DhmAg0NK.mjs.map +1 -0
- package/dist/_chunks/{Field-Caef4JjM.js → Field-1DLtcLAI.js} +948 -777
- package/dist/_chunks/Field-1DLtcLAI.js.map +1 -0
- package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-Cs62u5pl.mjs} +896 -724
- package/dist/_chunks/Field-Cs62u5pl.mjs.map +1 -0
- package/dist/_chunks/{Form-BzuAjtRq.js → Form-CqFA7F_V.js} +42 -41
- package/dist/_chunks/Form-CqFA7F_V.js.map +1 -0
- package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-zYHtzGUX.mjs} +43 -41
- package/dist/_chunks/Form-zYHtzGUX.mjs.map +1 -0
- package/dist/_chunks/{History-C17LiyRg.js → History-BblwXv7-.js} +149 -66
- package/dist/_chunks/History-BblwXv7-.js.map +1 -0
- package/dist/_chunks/{History-D6sbCJvo.mjs → History-DalgFQ3D.mjs} +149 -65
- package/dist/_chunks/History-DalgFQ3D.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-Cpy4QqNd.js} +61 -62
- package/dist/_chunks/ListConfigurationPage-Cpy4QqNd.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-DWy-vRzs.mjs} +58 -58
- package/dist/_chunks/ListConfigurationPage-DWy-vRzs.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-BkAwIW9s.mjs} +90 -106
- package/dist/_chunks/ListViewPage-BkAwIW9s.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-DFjn1DNW.js} +95 -111
- package/dist/_chunks/ListViewPage-DFjn1DNW.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-B9BCNNdL.mjs} +7 -7
- package/dist/_chunks/NoContentTypePage-B9BCNNdL.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-C-3ykoxs.js} +5 -5
- package/dist/_chunks/NoContentTypePage-C-3ykoxs.js.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-Bt_HWGat.mjs} +5 -6
- package/dist/_chunks/NoPermissionsPage-Bt_HWGat.mjs.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-DKLmDZnZ.js} +4 -5
- package/dist/_chunks/NoPermissionsPage-DKLmDZnZ.js.map +1 -0
- package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-CJmTbZ8T.mjs} +66 -56
- package/dist/_chunks/Relations-CJmTbZ8T.mjs.map +1 -0
- package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-CrxfoH2n.js} +70 -61
- package/dist/_chunks/Relations-CrxfoH2n.js.map +1 -0
- package/dist/_chunks/{en-MBPul9Su.mjs → en-Ux26r5pl.mjs} +7 -1
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-Ux26r5pl.mjs.map} +1 -1
- package/dist/_chunks/{en-C-V1_90f.js → en-fbKQxLGn.js} +7 -1
- package/dist/_chunks/{en-C-V1_90f.js.map → en-fbKQxLGn.js.map} +1 -1
- package/dist/_chunks/{index-X_2tafck.js → index-Buwn78Rt.js} +1507 -868
- package/dist/_chunks/index-Buwn78Rt.js.map +1 -0
- package/dist/_chunks/{index-DNVx8ssZ.mjs → index-D1344xdw.mjs} +1476 -836
- package/dist/_chunks/index-D1344xdw.mjs.map +1 -0
- package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-ChVuUpa1.mjs} +32 -27
- package/dist/_chunks/layout-ChVuUpa1.mjs.map +1 -0
- package/dist/_chunks/{layout-dBc7wN7L.js → layout-DRuJUpas.js} +32 -29
- package/dist/_chunks/layout-DRuJUpas.js.map +1 -0
- package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-B-deMCy4.mjs} +2 -2
- package/dist/_chunks/{relations-Dx7tMKJN.mjs.map → relations-B-deMCy4.mjs.map} +1 -1
- package/dist/_chunks/{relations-4pHtBrHJ.js → relations-DuoUwyJr.js} +2 -2
- package/dist/_chunks/{relations-4pHtBrHJ.js.map → relations-DuoUwyJr.js.map} +1 -1
- package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
- package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
- package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -4
- package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
- package/dist/admin/src/content-manager.d.ts +3 -3
- package/dist/admin/src/exports.d.ts +1 -0
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +5 -8
- package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
- package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
- package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +10 -4
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +10 -18
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +59 -52
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
- package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
- package/dist/admin/src/services/api.d.ts +2 -3
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +5 -5
- package/dist/admin/src/services/documents.d.ts +29 -17
- package/dist/admin/src/services/init.d.ts +2 -2
- package/dist/admin/src/services/relations.d.ts +3 -3
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/api.d.ts +4 -18
- package/dist/admin/src/utils/validation.d.ts +1 -6
- package/dist/server/index.js +547 -416
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +555 -424
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/single-types.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/index.d.ts +1 -1
- package/dist/server/src/history/services/history.d.ts +2 -4
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/index.d.ts +6 -2
- package/dist/server/src/history/services/index.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts +9 -0
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -0
- package/dist/server/src/history/services/utils.d.ts +41 -9
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/history/utils.d.ts +6 -2
- package/dist/server/src/history/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +18 -39
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts +13 -12
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +8 -29
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +18 -39
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts +8 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +14 -6
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/relations.d.ts +2 -2
- package/dist/shared/contracts/relations.d.ts.map +1 -1
- package/package.json +13 -14
- package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
- package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
- package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
- package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-Bm8lgcm6.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-CzOT5Kpj.js.map +0 -1
- package/dist/_chunks/Field-Caef4JjM.js.map +0 -1
- package/dist/_chunks/Field-Dlh0uGnL.mjs.map +0 -1
- package/dist/_chunks/Form-BzuAjtRq.js.map +0 -1
- package/dist/_chunks/Form-EnaQL_6L.mjs.map +0 -1
- package/dist/_chunks/History-C17LiyRg.js.map +0 -1
- package/dist/_chunks/History-D6sbCJvo.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Ce4qs7qE.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Dks5SX6f.js.map +0 -1
- package/dist/_chunks/ListViewPage-Be7S5aKL.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BwrZrPsh.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-CIPmYQMm.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-Cu5r1-JT.js.map +0 -1
- package/dist/_chunks/NoPermissionsPage-C-j6TEUF.js.map +0 -1
- package/dist/_chunks/NoPermissionsPage-DhJ7LYrr.mjs.map +0 -1
- package/dist/_chunks/Relations-CY7AtkDA.mjs.map +0 -1
- package/dist/_chunks/Relations-Czs-uZ-s.js.map +0 -1
- package/dist/_chunks/index-DNVx8ssZ.mjs.map +0 -1
- package/dist/_chunks/index-X_2tafck.js.map +0 -1
- package/dist/_chunks/layout-Dnh0PNp9.mjs.map +0 -1
- package/dist/_chunks/layout-dBc7wN7L.js.map +0 -1
- package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
- package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
- package/dist/_chunks/urls-DzZya_gm.js +0 -6
- package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
- package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
- package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
package/dist/server/index.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,
|
1
|
+
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, traverseEntity, pagination } from "@strapi/utils";
|
2
|
+
import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, isNil as isNil$1, getOr, propEq, merge, groupBy, castArray } from "lodash/fp";
|
3
3
|
import "@strapi/types";
|
4
4
|
import * as yup from "yup";
|
5
5
|
import { scheduleJob } from "node-schedule";
|
@@ -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 } = await getService(strapi2, "history").findVersionsPage({
|
57
|
+
const { results, pagination: pagination2 } = await getService(strapi2, "history").findVersionsPage({
|
58
58
|
query: {
|
59
59
|
...query,
|
60
60
|
...getValidPagination({ page: query.page, pageSize: query.pageSize })
|
@@ -73,7 +73,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
73
73
|
);
|
74
74
|
return {
|
75
75
|
data: sanitizedResults,
|
76
|
-
meta: { pagination }
|
76
|
+
meta: { pagination: pagination2 }
|
77
77
|
};
|
78
78
|
},
|
79
79
|
async restoreVersion(ctx) {
|
@@ -112,40 +112,65 @@ const FIELDS_TO_IGNORE = [
|
|
112
112
|
"strapi_stage",
|
113
113
|
"strapi_assignee"
|
114
114
|
];
|
115
|
-
const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
|
116
|
-
const sanitizedContentTypeSchemaAttributes = omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
|
117
|
-
const reduceDifferenceToAttributesObject = (diffKeys, source) => {
|
118
|
-
return diffKeys.reduce((previousAttributesObject, diffKey) => {
|
119
|
-
previousAttributesObject[diffKey] = source[diffKey];
|
120
|
-
return previousAttributesObject;
|
121
|
-
}, {});
|
122
|
-
};
|
123
|
-
const versionSchemaKeys = Object.keys(versionSchemaAttributes);
|
124
|
-
const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
|
125
|
-
const uniqueToContentType = difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
|
126
|
-
const added = reduceDifferenceToAttributesObject(
|
127
|
-
uniqueToContentType,
|
128
|
-
sanitizedContentTypeSchemaAttributes
|
129
|
-
);
|
130
|
-
const uniqueToVersion = difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
|
131
|
-
const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
|
132
|
-
return { added, removed };
|
133
|
-
};
|
134
115
|
const DEFAULT_RETENTION_DAYS = 90;
|
135
|
-
const
|
136
|
-
const
|
137
|
-
|
138
|
-
|
116
|
+
const createServiceUtils = ({ strapi: strapi2 }) => {
|
117
|
+
const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
|
118
|
+
const sanitizedContentTypeSchemaAttributes = omit(
|
119
|
+
FIELDS_TO_IGNORE,
|
120
|
+
contentTypeSchemaAttributes
|
121
|
+
);
|
122
|
+
const reduceDifferenceToAttributesObject = (diffKeys, source) => {
|
123
|
+
return diffKeys.reduce(
|
124
|
+
(previousAttributesObject, diffKey) => {
|
125
|
+
previousAttributesObject[diffKey] = source[diffKey];
|
126
|
+
return previousAttributesObject;
|
127
|
+
},
|
128
|
+
{}
|
129
|
+
);
|
130
|
+
};
|
131
|
+
const versionSchemaKeys = Object.keys(versionSchemaAttributes);
|
132
|
+
const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
|
133
|
+
const uniqueToContentType = difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
|
134
|
+
const added = reduceDifferenceToAttributesObject(
|
135
|
+
uniqueToContentType,
|
136
|
+
sanitizedContentTypeSchemaAttributes
|
137
|
+
);
|
138
|
+
const uniqueToVersion = difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
|
139
|
+
const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
|
140
|
+
return { added, removed };
|
139
141
|
};
|
140
|
-
const
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
142
|
+
const getRelationRestoreValue = async (versionRelationData, attribute) => {
|
143
|
+
if (Array.isArray(versionRelationData)) {
|
144
|
+
if (versionRelationData.length === 0)
|
145
|
+
return versionRelationData;
|
146
|
+
const existingAndMissingRelations = await Promise.all(
|
147
|
+
versionRelationData.map((relation) => {
|
148
|
+
return strapi2.documents(attribute.target).findOne({
|
149
|
+
documentId: relation.documentId,
|
150
|
+
locale: relation.locale || void 0
|
151
|
+
});
|
152
|
+
})
|
153
|
+
);
|
154
|
+
return existingAndMissingRelations.filter(
|
155
|
+
(relation) => relation !== null
|
156
|
+
);
|
147
157
|
}
|
148
|
-
return
|
158
|
+
return strapi2.documents(attribute.target).findOne({
|
159
|
+
documentId: versionRelationData.documentId,
|
160
|
+
locale: versionRelationData.locale || void 0
|
161
|
+
});
|
162
|
+
};
|
163
|
+
const getMediaRestoreValue = async (versionRelationData, attribute) => {
|
164
|
+
if (attribute.multiple) {
|
165
|
+
const existingAndMissingMedias = await Promise.all(
|
166
|
+
// @ts-expect-error Fix the type definitions so this isn't any
|
167
|
+
versionRelationData.map((media) => {
|
168
|
+
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
|
169
|
+
})
|
170
|
+
);
|
171
|
+
return existingAndMissingMedias.filter((media) => media != null);
|
172
|
+
}
|
173
|
+
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
149
174
|
};
|
150
175
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
151
176
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
@@ -161,6 +186,15 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
161
186
|
{}
|
162
187
|
);
|
163
188
|
};
|
189
|
+
const getRetentionDays = () => {
|
190
|
+
const featureConfig = strapi2.ee.features.get("cms-content-history");
|
191
|
+
const licenseRetentionDays = typeof featureConfig === "object" && featureConfig?.options.retentionDays;
|
192
|
+
const userRetentionDays = strapi2.config.get("admin.history.retentionDays");
|
193
|
+
if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
|
194
|
+
return userRetentionDays;
|
195
|
+
}
|
196
|
+
return Math.min(licenseRetentionDays, DEFAULT_RETENTION_DAYS);
|
197
|
+
};
|
164
198
|
const getVersionStatus = async (contentTypeUid, document) => {
|
165
199
|
const documentMetadataService = strapi2.plugin("content-manager").service("document-metadata");
|
166
200
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
@@ -172,6 +206,10 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
172
206
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
173
207
|
switch (attribute.type) {
|
174
208
|
case "relation": {
|
209
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
210
|
+
if (isMorphRelation) {
|
211
|
+
break;
|
212
|
+
}
|
175
213
|
const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
|
176
214
|
if (isVisible2) {
|
177
215
|
acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
|
@@ -202,80 +240,68 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
202
240
|
return acc;
|
203
241
|
}, {});
|
204
242
|
};
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
212
|
-
return next();
|
243
|
+
const buildMediaResponse = async (values) => {
|
244
|
+
return values.slice(0, 25).reduce(
|
245
|
+
async (currentRelationDataPromise, entry) => {
|
246
|
+
const currentRelationData = await currentRelationDataPromise;
|
247
|
+
if (!entry) {
|
248
|
+
return currentRelationData;
|
213
249
|
}
|
214
|
-
|
215
|
-
|
250
|
+
const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
|
251
|
+
if (relatedEntry) {
|
252
|
+
currentRelationData.results.push(relatedEntry);
|
253
|
+
} else {
|
254
|
+
currentRelationData.meta.missingCount += 1;
|
216
255
|
}
|
217
|
-
|
218
|
-
|
219
|
-
|
256
|
+
return currentRelationData;
|
257
|
+
},
|
258
|
+
Promise.resolve({
|
259
|
+
results: [],
|
260
|
+
meta: { missingCount: 0 }
|
261
|
+
})
|
262
|
+
);
|
263
|
+
};
|
264
|
+
const buildRelationReponse = async (values, attributeSchema) => {
|
265
|
+
return values.slice(0, 25).reduce(
|
266
|
+
async (currentRelationDataPromise, entry) => {
|
267
|
+
const currentRelationData = await currentRelationDataPromise;
|
268
|
+
if (!entry) {
|
269
|
+
return currentRelationData;
|
220
270
|
}
|
221
|
-
const
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
documentId: documentContext.documentId,
|
227
|
-
locale,
|
228
|
-
populate: getDeepPopulate2(contentTypeUid)
|
229
|
-
});
|
230
|
-
const status = await getVersionStatus(contentTypeUid, document);
|
231
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
232
|
-
const componentsSchemas = Object.keys(
|
233
|
-
attributesSchema
|
234
|
-
).reduce((currentComponentSchemas, key) => {
|
235
|
-
const fieldSchema = attributesSchema[key];
|
236
|
-
if (fieldSchema.type === "component") {
|
237
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
238
|
-
return {
|
239
|
-
...currentComponentSchemas,
|
240
|
-
[fieldSchema.component]: componentSchema
|
241
|
-
};
|
242
|
-
}
|
243
|
-
return currentComponentSchemas;
|
244
|
-
}, {});
|
245
|
-
await strapi2.db.transaction(async ({ onCommit }) => {
|
246
|
-
onCommit(() => {
|
247
|
-
this.createVersion({
|
248
|
-
contentType: contentTypeUid,
|
249
|
-
data: omit(FIELDS_TO_IGNORE, document),
|
250
|
-
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
251
|
-
componentsSchemas,
|
252
|
-
relatedDocumentId: documentContext.documentId,
|
253
|
-
locale,
|
254
|
-
status
|
255
|
-
});
|
271
|
+
const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
|
272
|
+
if (relatedEntry) {
|
273
|
+
currentRelationData.results.push({
|
274
|
+
...relatedEntry,
|
275
|
+
status: await getVersionStatus(attributeSchema.target, relatedEntry)
|
256
276
|
});
|
257
|
-
}
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
277
|
+
} else {
|
278
|
+
currentRelationData.meta.missingCount += 1;
|
279
|
+
}
|
280
|
+
return currentRelationData;
|
281
|
+
},
|
282
|
+
Promise.resolve({
|
283
|
+
results: [],
|
284
|
+
meta: { missingCount: 0 }
|
285
|
+
})
|
286
|
+
);
|
287
|
+
};
|
288
|
+
return {
|
289
|
+
getSchemaAttributesDiff,
|
290
|
+
getRelationRestoreValue,
|
291
|
+
getMediaRestoreValue,
|
292
|
+
getDefaultLocale,
|
293
|
+
getLocaleDictionary,
|
294
|
+
getRetentionDays,
|
295
|
+
getVersionStatus,
|
296
|
+
getDeepPopulate: getDeepPopulate2,
|
297
|
+
buildMediaResponse,
|
298
|
+
buildRelationReponse
|
299
|
+
};
|
300
|
+
};
|
301
|
+
const createHistoryService = ({ strapi: strapi2 }) => {
|
302
|
+
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
303
|
+
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
304
|
+
return {
|
279
305
|
async createVersion(historyVersionData) {
|
280
306
|
await query.create({
|
281
307
|
data: {
|
@@ -286,8 +312,8 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
286
312
|
});
|
287
313
|
},
|
288
314
|
async findVersionsPage(params) {
|
289
|
-
const locale = params.query.locale || await getDefaultLocale();
|
290
|
-
const [{ results, pagination }, localeDictionary] = await Promise.all([
|
315
|
+
const locale = params.query.locale || await serviceUtils.getDefaultLocale();
|
316
|
+
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
291
317
|
query.findPage({
|
292
318
|
...params.query,
|
293
319
|
where: {
|
@@ -300,78 +326,34 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
300
326
|
populate: ["createdBy"],
|
301
327
|
orderBy: [{ createdAt: "desc" }]
|
302
328
|
}),
|
303
|
-
getLocaleDictionary()
|
329
|
+
serviceUtils.getLocaleDictionary()
|
304
330
|
]);
|
305
|
-
const buildRelationReponse = async (values, attributeSchema) => {
|
306
|
-
return values.slice(0, 25).reduce(
|
307
|
-
async (currentRelationDataPromise, entry) => {
|
308
|
-
const currentRelationData = await currentRelationDataPromise;
|
309
|
-
if (!entry) {
|
310
|
-
return currentRelationData;
|
311
|
-
}
|
312
|
-
const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
|
313
|
-
const permissionChecker2 = getService$1("permission-checker").create({
|
314
|
-
userAbility: params.state.userAbility,
|
315
|
-
model: attributeSchema.target
|
316
|
-
});
|
317
|
-
const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
|
318
|
-
if (sanitizedEntry) {
|
319
|
-
currentRelationData.results.push({
|
320
|
-
...sanitizedEntry,
|
321
|
-
status: await getVersionStatus(attributeSchema.target, sanitizedEntry)
|
322
|
-
});
|
323
|
-
} else {
|
324
|
-
currentRelationData.meta.missingCount += 1;
|
325
|
-
}
|
326
|
-
return currentRelationData;
|
327
|
-
},
|
328
|
-
Promise.resolve({
|
329
|
-
results: [],
|
330
|
-
meta: { missingCount: 0 }
|
331
|
-
})
|
332
|
-
);
|
333
|
-
};
|
334
|
-
const buildMediaResponse = async (values) => {
|
335
|
-
return values.slice(0, 25).reduce(
|
336
|
-
async (currentRelationDataPromise, entry) => {
|
337
|
-
const currentRelationData = await currentRelationDataPromise;
|
338
|
-
if (!entry) {
|
339
|
-
return currentRelationData;
|
340
|
-
}
|
341
|
-
const permissionChecker2 = getService$1("permission-checker").create({
|
342
|
-
userAbility: params.state.userAbility,
|
343
|
-
model: "plugin::upload.file"
|
344
|
-
});
|
345
|
-
const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
|
346
|
-
const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
|
347
|
-
if (sanitizedEntry) {
|
348
|
-
currentRelationData.results.push(sanitizedEntry);
|
349
|
-
} else {
|
350
|
-
currentRelationData.meta.missingCount += 1;
|
351
|
-
}
|
352
|
-
return currentRelationData;
|
353
|
-
},
|
354
|
-
Promise.resolve({
|
355
|
-
results: [],
|
356
|
-
meta: { missingCount: 0 }
|
357
|
-
})
|
358
|
-
);
|
359
|
-
};
|
360
331
|
const populateEntryRelations = async (entry) => {
|
361
332
|
const entryWithRelations = await Object.entries(entry.schema).reduce(
|
362
333
|
async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
|
363
334
|
const attributeValue = entry.data[attributeKey];
|
364
335
|
const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
|
365
336
|
if (attributeSchema.type === "media") {
|
337
|
+
const permissionChecker2 = getService$1("permission-checker").create({
|
338
|
+
userAbility: params.state.userAbility,
|
339
|
+
model: "plugin::upload.file"
|
340
|
+
});
|
341
|
+
const response = await serviceUtils.buildMediaResponse(attributeValues);
|
342
|
+
const sanitizedResults = await Promise.all(
|
343
|
+
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
344
|
+
);
|
366
345
|
return {
|
367
346
|
...await currentDataWithRelations,
|
368
|
-
[attributeKey]:
|
347
|
+
[attributeKey]: {
|
348
|
+
results: sanitizedResults,
|
349
|
+
meta: response.meta
|
350
|
+
}
|
369
351
|
};
|
370
352
|
}
|
371
353
|
if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
|
372
354
|
if (attributeSchema.target === "admin::user") {
|
373
355
|
const adminUsers = await Promise.all(
|
374
|
-
attributeValues.map(
|
356
|
+
attributeValues.map((userToPopulate) => {
|
375
357
|
if (userToPopulate == null) {
|
376
358
|
return null;
|
377
359
|
}
|
@@ -388,9 +370,23 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
388
370
|
[attributeKey]: adminUsers
|
389
371
|
};
|
390
372
|
}
|
373
|
+
const permissionChecker2 = getService$1("permission-checker").create({
|
374
|
+
userAbility: params.state.userAbility,
|
375
|
+
model: attributeSchema.target
|
376
|
+
});
|
377
|
+
const response = await serviceUtils.buildRelationReponse(
|
378
|
+
attributeValues,
|
379
|
+
attributeSchema
|
380
|
+
);
|
381
|
+
const sanitizedResults = await Promise.all(
|
382
|
+
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
383
|
+
);
|
391
384
|
return {
|
392
385
|
...await currentDataWithRelations,
|
393
|
-
[attributeKey]:
|
386
|
+
[attributeKey]: {
|
387
|
+
results: sanitizedResults,
|
388
|
+
meta: response.meta
|
389
|
+
}
|
394
390
|
};
|
395
391
|
}
|
396
392
|
return currentDataWithRelations;
|
@@ -405,7 +401,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
405
401
|
...result,
|
406
402
|
data: await populateEntryRelations(result),
|
407
403
|
meta: {
|
408
|
-
unknownAttributes: getSchemaAttributesDiff(
|
404
|
+
unknownAttributes: serviceUtils.getSchemaAttributesDiff(
|
409
405
|
result.schema,
|
410
406
|
strapi2.getModel(params.query.contentType).attributes
|
411
407
|
)
|
@@ -416,13 +412,16 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
416
412
|
);
|
417
413
|
return {
|
418
414
|
results: formattedResults,
|
419
|
-
pagination
|
415
|
+
pagination: pagination2
|
420
416
|
};
|
421
417
|
},
|
422
418
|
async restoreVersion(versionId) {
|
423
419
|
const version = await query.findOne({ where: { id: versionId } });
|
424
420
|
const contentTypeSchemaAttributes = strapi2.getModel(version.contentType).attributes;
|
425
|
-
const schemaDiff = getSchemaAttributesDiff(
|
421
|
+
const schemaDiff = serviceUtils.getSchemaAttributesDiff(
|
422
|
+
version.schema,
|
423
|
+
contentTypeSchemaAttributes
|
424
|
+
);
|
426
425
|
const dataWithoutAddedAttributes = Object.keys(schemaDiff.added).reduce(
|
427
426
|
(currentData, addedKey) => {
|
428
427
|
currentData[addedKey] = null;
|
@@ -435,61 +434,26 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
435
434
|
FIELDS_TO_IGNORE,
|
436
435
|
contentTypeSchemaAttributes
|
437
436
|
);
|
438
|
-
const
|
439
|
-
|
440
|
-
|
441
|
-
const
|
442
|
-
if (
|
437
|
+
const reducer = async.reduce(Object.entries(sanitizedSchemaAttributes));
|
438
|
+
const dataWithoutMissingRelations = await reducer(
|
439
|
+
async (previousRelationAttributes, [name, attribute]) => {
|
440
|
+
const versionRelationData = version.data[name];
|
441
|
+
if (!versionRelationData) {
|
443
442
|
return previousRelationAttributes;
|
444
443
|
}
|
445
444
|
if (attribute.type === "relation" && // TODO: handle polymorphic relations
|
446
445
|
attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
|
447
|
-
|
448
|
-
|
449
|
-
return previousRelationAttributes;
|
450
|
-
const existingAndMissingRelations = await Promise.all(
|
451
|
-
relationData.map((relation) => {
|
452
|
-
return strapi2.documents(attribute.target).findOne({
|
453
|
-
documentId: relation.documentId,
|
454
|
-
locale: relation.locale || void 0
|
455
|
-
});
|
456
|
-
})
|
457
|
-
);
|
458
|
-
const existingRelations = existingAndMissingRelations.filter(
|
459
|
-
(relation) => relation !== null
|
460
|
-
);
|
461
|
-
previousRelationAttributes[name] = existingRelations;
|
462
|
-
} else {
|
463
|
-
const existingRelation = await strapi2.documents(attribute.target).findOne({
|
464
|
-
documentId: relationData.documentId,
|
465
|
-
locale: relationData.locale || void 0
|
466
|
-
});
|
467
|
-
if (!existingRelation) {
|
468
|
-
previousRelationAttributes[name] = null;
|
469
|
-
}
|
470
|
-
}
|
446
|
+
const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
|
447
|
+
previousRelationAttributes[name] = data2;
|
471
448
|
}
|
472
449
|
if (attribute.type === "media") {
|
473
|
-
|
474
|
-
|
475
|
-
// @ts-expect-error Fix the type definitions so this isn't any
|
476
|
-
relationData.map((media) => {
|
477
|
-
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
|
478
|
-
})
|
479
|
-
);
|
480
|
-
const existingMedias = existingAndMissingMedias.filter((media) => media != null);
|
481
|
-
previousRelationAttributes[name] = existingMedias;
|
482
|
-
} else {
|
483
|
-
const existingMedia = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: version.data[name].id } });
|
484
|
-
if (!existingMedia) {
|
485
|
-
previousRelationAttributes[name] = null;
|
486
|
-
}
|
487
|
-
}
|
450
|
+
const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
|
451
|
+
previousRelationAttributes[name] = data2;
|
488
452
|
}
|
489
453
|
return previousRelationAttributes;
|
490
454
|
},
|
491
455
|
// Clone to avoid mutating the original version data
|
492
|
-
|
456
|
+
structuredClone(dataWithoutAddedAttributes)
|
493
457
|
);
|
494
458
|
const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
|
495
459
|
const restoredDocument = await strapi2.documents(version.contentType).update({
|
@@ -504,8 +468,102 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
504
468
|
}
|
505
469
|
};
|
506
470
|
};
|
471
|
+
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
472
|
+
const state = {
|
473
|
+
deleteExpiredJob: null,
|
474
|
+
isInitialized: false
|
475
|
+
};
|
476
|
+
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
477
|
+
return {
|
478
|
+
async bootstrap() {
|
479
|
+
if (state.isInitialized) {
|
480
|
+
return;
|
481
|
+
}
|
482
|
+
strapi2.documents.use(async (context, next) => {
|
483
|
+
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
484
|
+
return next();
|
485
|
+
}
|
486
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
487
|
+
return next();
|
488
|
+
}
|
489
|
+
if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
490
|
+
return next();
|
491
|
+
}
|
492
|
+
const contentTypeUid = context.contentType.uid;
|
493
|
+
if (!contentTypeUid.startsWith("api::")) {
|
494
|
+
return next();
|
495
|
+
}
|
496
|
+
const result = await next();
|
497
|
+
const documentContext = {
|
498
|
+
documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
|
499
|
+
locale: context.params?.locale
|
500
|
+
};
|
501
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
502
|
+
const locale = documentContext.locale || defaultLocale;
|
503
|
+
if (Array.isArray(locale)) {
|
504
|
+
strapi2.log.warn(
|
505
|
+
"[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
|
506
|
+
);
|
507
|
+
return next();
|
508
|
+
}
|
509
|
+
const document = await strapi2.documents(contentTypeUid).findOne({
|
510
|
+
documentId: documentContext.documentId,
|
511
|
+
locale,
|
512
|
+
populate: serviceUtils.getDeepPopulate(contentTypeUid)
|
513
|
+
});
|
514
|
+
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
515
|
+
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
516
|
+
const componentsSchemas = Object.keys(
|
517
|
+
attributesSchema
|
518
|
+
).reduce((currentComponentSchemas, key) => {
|
519
|
+
const fieldSchema = attributesSchema[key];
|
520
|
+
if (fieldSchema.type === "component") {
|
521
|
+
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
522
|
+
return {
|
523
|
+
...currentComponentSchemas,
|
524
|
+
[fieldSchema.component]: componentSchema
|
525
|
+
};
|
526
|
+
}
|
527
|
+
return currentComponentSchemas;
|
528
|
+
}, {});
|
529
|
+
await strapi2.db.transaction(async ({ onCommit }) => {
|
530
|
+
onCommit(() => {
|
531
|
+
getService(strapi2, "history").createVersion({
|
532
|
+
contentType: contentTypeUid,
|
533
|
+
data: omit(FIELDS_TO_IGNORE, document),
|
534
|
+
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
535
|
+
componentsSchemas,
|
536
|
+
relatedDocumentId: documentContext.documentId,
|
537
|
+
locale,
|
538
|
+
status
|
539
|
+
});
|
540
|
+
});
|
541
|
+
});
|
542
|
+
return result;
|
543
|
+
});
|
544
|
+
state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
|
545
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
546
|
+
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
547
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
548
|
+
where: {
|
549
|
+
created_at: {
|
550
|
+
$lt: expirationDate.toISOString()
|
551
|
+
}
|
552
|
+
}
|
553
|
+
});
|
554
|
+
});
|
555
|
+
state.isInitialized = true;
|
556
|
+
},
|
557
|
+
async destroy() {
|
558
|
+
if (state.deleteExpiredJob) {
|
559
|
+
state.deleteExpiredJob.cancel();
|
560
|
+
}
|
561
|
+
}
|
562
|
+
};
|
563
|
+
};
|
507
564
|
const services$1 = {
|
508
|
-
history: createHistoryService
|
565
|
+
history: createHistoryService,
|
566
|
+
lifecycles: createLifecyclesService
|
509
567
|
};
|
510
568
|
const info = { pluginName: "content-manager", type: "admin" };
|
511
569
|
const historyVersionRouter = {
|
@@ -585,10 +643,10 @@ const getFeature = () => {
|
|
585
643
|
strapi2.get("models").add(historyVersion);
|
586
644
|
},
|
587
645
|
bootstrap({ strapi: strapi2 }) {
|
588
|
-
getService(strapi2, "
|
646
|
+
getService(strapi2, "lifecycles").bootstrap();
|
589
647
|
},
|
590
648
|
destroy({ strapi: strapi2 }) {
|
591
|
-
getService(strapi2, "
|
649
|
+
getService(strapi2, "lifecycles").destroy();
|
592
650
|
},
|
593
651
|
controllers: controllers$1,
|
594
652
|
services: services$1,
|
@@ -1407,7 +1465,7 @@ const { PaginationError, ValidationError } = errors;
|
|
1407
1465
|
const TYPES = ["singleType", "collectionType"];
|
1408
1466
|
const kindSchema = yup$1.string().oneOf(TYPES).nullable();
|
1409
1467
|
const bulkActionInputSchema = yup$1.object({
|
1410
|
-
|
1468
|
+
documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
|
1411
1469
|
}).required();
|
1412
1470
|
const generateUIDInputSchema = yup$1.object({
|
1413
1471
|
contentTypeUID: yup$1.string().required(),
|
@@ -1506,15 +1564,47 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1506
1564
|
}
|
1507
1565
|
}, body);
|
1508
1566
|
};
|
1509
|
-
const
|
1567
|
+
const singleLocaleSchema = yup$1.string().nullable();
|
1568
|
+
const multipleLocaleSchema = yup$1.lazy(
|
1569
|
+
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1570
|
+
);
|
1571
|
+
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1572
|
+
const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
|
1573
|
+
const { allowMultipleLocales } = opts;
|
1510
1574
|
const { locale, status, ...rest } = request || {};
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1575
|
+
const schema = yup$1.object().shape({
|
1576
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1577
|
+
status: statusSchema
|
1578
|
+
});
|
1579
|
+
try {
|
1580
|
+
await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1581
|
+
return { locale, status, ...rest };
|
1582
|
+
} catch (error) {
|
1583
|
+
throw new errors.ValidationError(`Validation error: ${error.message}`);
|
1516
1584
|
}
|
1517
|
-
|
1585
|
+
};
|
1586
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1587
|
+
const documentMetadata2 = getService$1("document-metadata");
|
1588
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1589
|
+
let {
|
1590
|
+
meta: { availableLocales, availableStatus }
|
1591
|
+
} = serviceOutput;
|
1592
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1593
|
+
availableLocales = await async.map(
|
1594
|
+
availableLocales,
|
1595
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1596
|
+
);
|
1597
|
+
availableStatus = await async.map(
|
1598
|
+
availableStatus,
|
1599
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1600
|
+
);
|
1601
|
+
return {
|
1602
|
+
...serviceOutput,
|
1603
|
+
meta: {
|
1604
|
+
availableLocales,
|
1605
|
+
availableStatus
|
1606
|
+
}
|
1607
|
+
};
|
1518
1608
|
};
|
1519
1609
|
const createDocument = async (ctx, opts) => {
|
1520
1610
|
const { userAbility, user } = ctx.state;
|
@@ -1529,7 +1619,7 @@ const createDocument = async (ctx, opts) => {
|
|
1529
1619
|
const setCreator = setCreatorFields({ user });
|
1530
1620
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1531
1621
|
const sanitizedBody = await sanitizeFn(body);
|
1532
|
-
const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
|
1622
|
+
const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
|
1533
1623
|
return documentManager2.create(model, {
|
1534
1624
|
data: sanitizedBody,
|
1535
1625
|
locale,
|
@@ -1548,7 +1638,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1548
1638
|
}
|
1549
1639
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1550
1640
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1551
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1641
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
1552
1642
|
const [documentVersion, documentExists] = await Promise.all([
|
1553
1643
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1554
1644
|
documentManager2.exists(model, id)
|
@@ -1586,8 +1676,8 @@ const collectionTypes = {
|
|
1586
1676
|
}
|
1587
1677
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1588
1678
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1589
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
1590
|
-
const { results: documents, pagination } = await documentManager2.findPage(
|
1679
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
1680
|
+
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1591
1681
|
{ ...permissionQuery, populate, locale, status },
|
1592
1682
|
model
|
1593
1683
|
);
|
@@ -1608,21 +1698,20 @@ const collectionTypes = {
|
|
1608
1698
|
);
|
1609
1699
|
ctx.body = {
|
1610
1700
|
results,
|
1611
|
-
pagination
|
1701
|
+
pagination: pagination2
|
1612
1702
|
};
|
1613
1703
|
},
|
1614
1704
|
async findOne(ctx) {
|
1615
1705
|
const { userAbility } = ctx.state;
|
1616
1706
|
const { model, id } = ctx.params;
|
1617
1707
|
const documentManager2 = getService$1("document-manager");
|
1618
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1619
1708
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1620
1709
|
if (permissionChecker2.cannot.read()) {
|
1621
1710
|
return ctx.forbidden();
|
1622
1711
|
}
|
1623
1712
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1624
1713
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1625
|
-
const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
|
1714
|
+
const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
|
1626
1715
|
const version = await documentManager2.findOne(id, model, {
|
1627
1716
|
populate,
|
1628
1717
|
locale,
|
@@ -1633,8 +1722,10 @@ const collectionTypes = {
|
|
1633
1722
|
if (!exists) {
|
1634
1723
|
return ctx.notFound();
|
1635
1724
|
}
|
1636
|
-
const { meta } = await
|
1725
|
+
const { meta } = await formatDocumentWithMetadata(
|
1726
|
+
permissionChecker2,
|
1637
1727
|
model,
|
1728
|
+
// @ts-expect-error TODO: fix
|
1638
1729
|
{ id, locale, publishedAt: null },
|
1639
1730
|
{ availableLocales: true, availableStatus: false }
|
1640
1731
|
);
|
@@ -1645,12 +1736,11 @@ const collectionTypes = {
|
|
1645
1736
|
return ctx.forbidden();
|
1646
1737
|
}
|
1647
1738
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1648
|
-
ctx.body = await
|
1739
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1649
1740
|
},
|
1650
1741
|
async create(ctx) {
|
1651
1742
|
const { userAbility } = ctx.state;
|
1652
1743
|
const { model } = ctx.params;
|
1653
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1654
1744
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1655
1745
|
const [totalEntries, document] = await Promise.all([
|
1656
1746
|
strapi.db.query(model).count(),
|
@@ -1658,7 +1748,7 @@ const collectionTypes = {
|
|
1658
1748
|
]);
|
1659
1749
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1660
1750
|
ctx.status = 201;
|
1661
|
-
ctx.body = await
|
1751
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1662
1752
|
// Empty metadata as it's not relevant for a new document
|
1663
1753
|
availableLocales: false,
|
1664
1754
|
availableStatus: false
|
@@ -1672,25 +1762,23 @@ const collectionTypes = {
|
|
1672
1762
|
async update(ctx) {
|
1673
1763
|
const { userAbility } = ctx.state;
|
1674
1764
|
const { model } = ctx.params;
|
1675
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1676
1765
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1677
1766
|
const updatedVersion = await updateDocument(ctx);
|
1678
1767
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1679
|
-
ctx.body = await
|
1768
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1680
1769
|
},
|
1681
1770
|
async clone(ctx) {
|
1682
1771
|
const { userAbility, user } = ctx.state;
|
1683
1772
|
const { model, sourceId: id } = ctx.params;
|
1684
1773
|
const { body } = ctx.request;
|
1685
1774
|
const documentManager2 = getService$1("document-manager");
|
1686
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1687
1775
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1688
1776
|
if (permissionChecker2.cannot.create()) {
|
1689
1777
|
return ctx.forbidden();
|
1690
1778
|
}
|
1691
1779
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1692
1780
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1693
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1781
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
1694
1782
|
const document = await documentManager2.findOne(id, model, {
|
1695
1783
|
populate,
|
1696
1784
|
locale,
|
@@ -1706,7 +1794,7 @@ const collectionTypes = {
|
|
1706
1794
|
const sanitizedBody = await sanitizeFn(body);
|
1707
1795
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1708
1796
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1709
|
-
ctx.body = await
|
1797
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1710
1798
|
// Empty metadata as it's not relevant for a new document
|
1711
1799
|
availableLocales: false,
|
1712
1800
|
availableStatus: false
|
@@ -1735,7 +1823,7 @@ const collectionTypes = {
|
|
1735
1823
|
}
|
1736
1824
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1737
1825
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1738
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
1826
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query);
|
1739
1827
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1740
1828
|
if (documentLocales.length === 0) {
|
1741
1829
|
return ctx.notFound();
|
@@ -1757,7 +1845,6 @@ const collectionTypes = {
|
|
1757
1845
|
const { id, model } = ctx.params;
|
1758
1846
|
const { body } = ctx.request;
|
1759
1847
|
const documentManager2 = getService$1("document-manager");
|
1760
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1761
1848
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1762
1849
|
if (permissionChecker2.cannot.publish()) {
|
1763
1850
|
return ctx.forbidden();
|
@@ -1769,21 +1856,25 @@ const collectionTypes = {
|
|
1769
1856
|
if (permissionChecker2.cannot.publish(document)) {
|
1770
1857
|
throw new errors.ForbiddenError();
|
1771
1858
|
}
|
1772
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1773
|
-
|
1859
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
1860
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1774
1861
|
locale
|
1775
1862
|
// TODO: Allow setting creator fields on publish
|
1776
1863
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1777
1864
|
});
|
1865
|
+
if (!publishResult || publishResult.length === 0) {
|
1866
|
+
throw new errors.NotFoundError("Document not found or already published.");
|
1867
|
+
}
|
1868
|
+
return publishResult[0];
|
1778
1869
|
});
|
1779
1870
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1780
|
-
ctx.body = await
|
1871
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1781
1872
|
},
|
1782
1873
|
async bulkPublish(ctx) {
|
1783
1874
|
const { userAbility } = ctx.state;
|
1784
1875
|
const { model } = ctx.params;
|
1785
1876
|
const { body } = ctx.request;
|
1786
|
-
const {
|
1877
|
+
const { documentIds } = body;
|
1787
1878
|
await validateBulkActionInput(body);
|
1788
1879
|
const documentManager2 = getService$1("document-manager");
|
1789
1880
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1792,8 +1883,11 @@ const collectionTypes = {
|
|
1792
1883
|
}
|
1793
1884
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1794
1885
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1795
|
-
const
|
1796
|
-
const
|
1886
|
+
const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
|
1887
|
+
const entityPromises = documentIds.map(
|
1888
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1889
|
+
);
|
1890
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1797
1891
|
for (const entity of entities) {
|
1798
1892
|
if (!entity) {
|
1799
1893
|
return ctx.notFound();
|
@@ -1802,24 +1896,25 @@ const collectionTypes = {
|
|
1802
1896
|
return ctx.forbidden();
|
1803
1897
|
}
|
1804
1898
|
}
|
1805
|
-
const
|
1899
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1806
1900
|
ctx.body = { count };
|
1807
1901
|
},
|
1808
1902
|
async bulkUnpublish(ctx) {
|
1809
1903
|
const { userAbility } = ctx.state;
|
1810
1904
|
const { model } = ctx.params;
|
1811
1905
|
const { body } = ctx.request;
|
1812
|
-
const {
|
1906
|
+
const { documentIds } = body;
|
1813
1907
|
await validateBulkActionInput(body);
|
1814
1908
|
const documentManager2 = getService$1("document-manager");
|
1815
1909
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1816
1910
|
if (permissionChecker2.cannot.unpublish()) {
|
1817
1911
|
return ctx.forbidden();
|
1818
1912
|
}
|
1819
|
-
const
|
1820
|
-
const
|
1821
|
-
|
1822
|
-
|
1913
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
1914
|
+
const entityPromises = documentIds.map(
|
1915
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1916
|
+
);
|
1917
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1823
1918
|
for (const entity of entities) {
|
1824
1919
|
if (!entity) {
|
1825
1920
|
return ctx.notFound();
|
@@ -1828,7 +1923,8 @@ const collectionTypes = {
|
|
1828
1923
|
return ctx.forbidden();
|
1829
1924
|
}
|
1830
1925
|
}
|
1831
|
-
const
|
1926
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
1927
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1832
1928
|
ctx.body = { count };
|
1833
1929
|
},
|
1834
1930
|
async unpublish(ctx) {
|
@@ -1838,7 +1934,6 @@ const collectionTypes = {
|
|
1838
1934
|
body: { discardDraft, ...body }
|
1839
1935
|
} = ctx.request;
|
1840
1936
|
const documentManager2 = getService$1("document-manager");
|
1841
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1842
1937
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1843
1938
|
if (permissionChecker2.cannot.unpublish()) {
|
1844
1939
|
return ctx.forbidden();
|
@@ -1848,7 +1943,7 @@ const collectionTypes = {
|
|
1848
1943
|
}
|
1849
1944
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1850
1945
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1851
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1946
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
1852
1947
|
const document = await documentManager2.findOne(id, model, {
|
1853
1948
|
populate,
|
1854
1949
|
locale,
|
@@ -1870,7 +1965,7 @@ const collectionTypes = {
|
|
1870
1965
|
ctx.body = await async.pipe(
|
1871
1966
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1872
1967
|
permissionChecker2.sanitizeOutput,
|
1873
|
-
(document2) =>
|
1968
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1874
1969
|
)(document);
|
1875
1970
|
});
|
1876
1971
|
},
|
@@ -1879,14 +1974,13 @@ const collectionTypes = {
|
|
1879
1974
|
const { id, model } = ctx.params;
|
1880
1975
|
const { body } = ctx.request;
|
1881
1976
|
const documentManager2 = getService$1("document-manager");
|
1882
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1883
1977
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1884
1978
|
if (permissionChecker2.cannot.discard()) {
|
1885
1979
|
return ctx.forbidden();
|
1886
1980
|
}
|
1887
1981
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1888
1982
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1889
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1983
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
1890
1984
|
const document = await documentManager2.findOne(id, model, {
|
1891
1985
|
populate,
|
1892
1986
|
locale,
|
@@ -1901,14 +1995,14 @@ const collectionTypes = {
|
|
1901
1995
|
ctx.body = await async.pipe(
|
1902
1996
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1903
1997
|
permissionChecker2.sanitizeOutput,
|
1904
|
-
(document2) =>
|
1998
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1905
1999
|
)(document);
|
1906
2000
|
},
|
1907
2001
|
async bulkDelete(ctx) {
|
1908
2002
|
const { userAbility } = ctx.state;
|
1909
2003
|
const { model } = ctx.params;
|
1910
2004
|
const { query, body } = ctx.request;
|
1911
|
-
const {
|
2005
|
+
const { documentIds } = body;
|
1912
2006
|
await validateBulkActionInput(body);
|
1913
2007
|
const documentManager2 = getService$1("document-manager");
|
1914
2008
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1916,14 +2010,22 @@ const collectionTypes = {
|
|
1916
2010
|
return ctx.forbidden();
|
1917
2011
|
}
|
1918
2012
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1919
|
-
const
|
1920
|
-
const
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
2013
|
+
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2014
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
2015
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2016
|
+
populate,
|
2017
|
+
locale
|
2018
|
+
});
|
2019
|
+
if (documentLocales.length === 0) {
|
2020
|
+
return ctx.notFound();
|
2021
|
+
}
|
2022
|
+
for (const document of documentLocales) {
|
2023
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2024
|
+
return ctx.forbidden();
|
1924
2025
|
}
|
1925
|
-
}
|
1926
|
-
const
|
2026
|
+
}
|
2027
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2028
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1927
2029
|
ctx.body = { count };
|
1928
2030
|
},
|
1929
2031
|
async countDraftRelations(ctx) {
|
@@ -1936,7 +2038,7 @@ const collectionTypes = {
|
|
1936
2038
|
}
|
1937
2039
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1938
2040
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1939
|
-
const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
|
2041
|
+
const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
|
1940
2042
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
1941
2043
|
if (!entity) {
|
1942
2044
|
return ctx.notFound();
|
@@ -1951,7 +2053,7 @@ const collectionTypes = {
|
|
1951
2053
|
},
|
1952
2054
|
async countManyEntriesDraftRelations(ctx) {
|
1953
2055
|
const { userAbility } = ctx.state;
|
1954
|
-
const ids = ctx.request.query.
|
2056
|
+
const ids = ctx.request.query.documentIds;
|
1955
2057
|
const locale = ctx.request.query.locale;
|
1956
2058
|
const { model } = ctx.params;
|
1957
2059
|
const documentManager2 = getService$1("document-manager");
|
@@ -1959,16 +2061,16 @@ const collectionTypes = {
|
|
1959
2061
|
if (permissionChecker2.cannot.read()) {
|
1960
2062
|
return ctx.forbidden();
|
1961
2063
|
}
|
1962
|
-
const
|
2064
|
+
const documents = await documentManager2.findMany(
|
1963
2065
|
{
|
1964
2066
|
filters: {
|
1965
|
-
|
2067
|
+
documentId: ids
|
1966
2068
|
},
|
1967
2069
|
locale
|
1968
2070
|
},
|
1969
2071
|
model
|
1970
2072
|
);
|
1971
|
-
if (!
|
2073
|
+
if (!documents) {
|
1972
2074
|
return ctx.notFound();
|
1973
2075
|
}
|
1974
2076
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2464,7 +2566,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2464
2566
|
throw new errors.ForbiddenError();
|
2465
2567
|
}
|
2466
2568
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2467
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2569
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
2468
2570
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2469
2571
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2470
2572
|
// Find the first document to check if it exists
|
@@ -2501,12 +2603,11 @@ const singleTypes = {
|
|
2501
2603
|
const { model } = ctx.params;
|
2502
2604
|
const { query = {} } = ctx.request;
|
2503
2605
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2504
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2505
2606
|
if (permissionChecker2.cannot.read()) {
|
2506
2607
|
return ctx.forbidden();
|
2507
2608
|
}
|
2508
2609
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2509
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2610
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
2510
2611
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2511
2612
|
if (!version) {
|
2512
2613
|
if (permissionChecker2.cannot.create()) {
|
@@ -2516,8 +2617,10 @@ const singleTypes = {
|
|
2516
2617
|
if (!document) {
|
2517
2618
|
return ctx.notFound();
|
2518
2619
|
}
|
2519
|
-
const { meta } = await
|
2620
|
+
const { meta } = await formatDocumentWithMetadata(
|
2621
|
+
permissionChecker2,
|
2520
2622
|
model,
|
2623
|
+
// @ts-expect-error - fix types
|
2521
2624
|
{ id: document.documentId, locale, publishedAt: null },
|
2522
2625
|
{ availableLocales: true, availableStatus: false }
|
2523
2626
|
);
|
@@ -2528,16 +2631,15 @@ const singleTypes = {
|
|
2528
2631
|
return ctx.forbidden();
|
2529
2632
|
}
|
2530
2633
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2531
|
-
ctx.body = await
|
2634
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2532
2635
|
},
|
2533
2636
|
async createOrUpdate(ctx) {
|
2534
2637
|
const { userAbility } = ctx.state;
|
2535
2638
|
const { model } = ctx.params;
|
2536
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2537
2639
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2538
2640
|
const document = await createOrUpdateDocument(ctx);
|
2539
2641
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2540
|
-
ctx.body = await
|
2642
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2541
2643
|
},
|
2542
2644
|
async delete(ctx) {
|
2543
2645
|
const { userAbility } = ctx.state;
|
@@ -2550,7 +2652,7 @@ const singleTypes = {
|
|
2550
2652
|
}
|
2551
2653
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2552
2654
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2553
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2655
|
+
const { locale } = await getDocumentLocaleAndStatus(query);
|
2554
2656
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2555
2657
|
populate,
|
2556
2658
|
locale
|
@@ -2573,7 +2675,6 @@ const singleTypes = {
|
|
2573
2675
|
const { model } = ctx.params;
|
2574
2676
|
const { query = {} } = ctx.request;
|
2575
2677
|
const documentManager2 = getService$1("document-manager");
|
2576
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2577
2678
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2578
2679
|
if (permissionChecker2.cannot.publish()) {
|
2579
2680
|
return ctx.forbidden();
|
@@ -2588,11 +2689,12 @@ const singleTypes = {
|
|
2588
2689
|
if (permissionChecker2.cannot.publish(document)) {
|
2589
2690
|
throw new errors.ForbiddenError();
|
2590
2691
|
}
|
2591
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2592
|
-
|
2692
|
+
const { locale } = await getDocumentLocaleAndStatus(document);
|
2693
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2694
|
+
return publishResult.at(0);
|
2593
2695
|
});
|
2594
2696
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2595
|
-
ctx.body = await
|
2697
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2596
2698
|
},
|
2597
2699
|
async unpublish(ctx) {
|
2598
2700
|
const { userAbility } = ctx.state;
|
@@ -2602,7 +2704,6 @@ const singleTypes = {
|
|
2602
2704
|
query = {}
|
2603
2705
|
} = ctx.request;
|
2604
2706
|
const documentManager2 = getService$1("document-manager");
|
2605
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2606
2707
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2607
2708
|
if (permissionChecker2.cannot.unpublish()) {
|
2608
2709
|
return ctx.forbidden();
|
@@ -2611,7 +2712,7 @@ const singleTypes = {
|
|
2611
2712
|
return ctx.forbidden();
|
2612
2713
|
}
|
2613
2714
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2614
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2715
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
2615
2716
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2616
2717
|
if (!document) {
|
2617
2718
|
return ctx.notFound();
|
@@ -2629,7 +2730,7 @@ const singleTypes = {
|
|
2629
2730
|
ctx.body = await async.pipe(
|
2630
2731
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2631
2732
|
permissionChecker2.sanitizeOutput,
|
2632
|
-
(document2) =>
|
2733
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2633
2734
|
)(document);
|
2634
2735
|
});
|
2635
2736
|
},
|
@@ -2638,13 +2739,12 @@ const singleTypes = {
|
|
2638
2739
|
const { model } = ctx.params;
|
2639
2740
|
const { body, query = {} } = ctx.request;
|
2640
2741
|
const documentManager2 = getService$1("document-manager");
|
2641
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2642
2742
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2643
2743
|
if (permissionChecker2.cannot.discard()) {
|
2644
2744
|
return ctx.forbidden();
|
2645
2745
|
}
|
2646
2746
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2647
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2747
|
+
const { locale } = await getDocumentLocaleAndStatus(body);
|
2648
2748
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2649
2749
|
if (!document) {
|
2650
2750
|
return ctx.notFound();
|
@@ -2655,7 +2755,7 @@ const singleTypes = {
|
|
2655
2755
|
ctx.body = await async.pipe(
|
2656
2756
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2657
2757
|
permissionChecker2.sanitizeOutput,
|
2658
|
-
(document2) =>
|
2758
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2659
2759
|
)(document);
|
2660
2760
|
},
|
2661
2761
|
async countDraftRelations(ctx) {
|
@@ -2664,7 +2764,7 @@ const singleTypes = {
|
|
2664
2764
|
const { query } = ctx.request;
|
2665
2765
|
const documentManager2 = getService$1("document-manager");
|
2666
2766
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2667
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2767
|
+
const { locale } = await getDocumentLocaleAndStatus(query);
|
2668
2768
|
if (permissionChecker2.cannot.read()) {
|
2669
2769
|
return ctx.forbidden();
|
2670
2770
|
}
|
@@ -2685,7 +2785,7 @@ const uid$1 = {
|
|
2685
2785
|
async generateUID(ctx) {
|
2686
2786
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2687
2787
|
const { query = {} } = ctx.request;
|
2688
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2788
|
+
const { locale } = await getDocumentLocaleAndStatus(query);
|
2689
2789
|
await validateUIDField(contentTypeUID, field);
|
2690
2790
|
const uidService = getService$1("uid");
|
2691
2791
|
ctx.body = {
|
@@ -2697,7 +2797,7 @@ const uid$1 = {
|
|
2697
2797
|
ctx.request.body
|
2698
2798
|
);
|
2699
2799
|
const { query = {} } = ctx.request;
|
2700
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2800
|
+
const { locale } = await getDocumentLocaleAndStatus(query);
|
2701
2801
|
await validateUIDField(contentTypeUID, field);
|
2702
2802
|
const uidService = getService$1("uid");
|
2703
2803
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -3488,7 +3588,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3488
3588
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3489
3589
|
}
|
3490
3590
|
});
|
3491
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
|
3591
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
|
3492
3592
|
const { isAnyToMany } = strapiUtils.relations;
|
3493
3593
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
|
3494
3594
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3579,6 +3679,42 @@ const getDeepPopulate = (uid2, {
|
|
3579
3679
|
{}
|
3580
3680
|
);
|
3581
3681
|
};
|
3682
|
+
const getValidatableFieldsPopulate = (uid2, {
|
3683
|
+
initialPopulate = {},
|
3684
|
+
countMany = false,
|
3685
|
+
countOne = false,
|
3686
|
+
maxLevel = Infinity
|
3687
|
+
} = {}, level = 1) => {
|
3688
|
+
if (level > maxLevel) {
|
3689
|
+
return {};
|
3690
|
+
}
|
3691
|
+
const model = strapi.getModel(uid2);
|
3692
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3693
|
+
if (!getDoesAttributeRequireValidation(attribute)) {
|
3694
|
+
return populateAcc;
|
3695
|
+
}
|
3696
|
+
if (isScalarAttribute(attribute)) {
|
3697
|
+
return merge(populateAcc, {
|
3698
|
+
[attributeName]: true
|
3699
|
+
});
|
3700
|
+
}
|
3701
|
+
return merge(
|
3702
|
+
populateAcc,
|
3703
|
+
getPopulateFor(
|
3704
|
+
attributeName,
|
3705
|
+
model,
|
3706
|
+
{
|
3707
|
+
// @ts-expect-error - improve types
|
3708
|
+
initialPopulate: initialPopulate?.[attributeName],
|
3709
|
+
countMany,
|
3710
|
+
countOne,
|
3711
|
+
maxLevel
|
3712
|
+
},
|
3713
|
+
level
|
3714
|
+
)
|
3715
|
+
);
|
3716
|
+
}, {});
|
3717
|
+
};
|
3582
3718
|
const getDeepPopulateDraftCount = (uid2) => {
|
3583
3719
|
const model = strapi.getModel(uid2);
|
3584
3720
|
let hasRelations = false;
|
@@ -3600,22 +3736,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3600
3736
|
attribute.component
|
3601
3737
|
);
|
3602
3738
|
if (childHasRelations) {
|
3603
|
-
populateAcc[attributeName] = {
|
3739
|
+
populateAcc[attributeName] = {
|
3740
|
+
populate: populate2
|
3741
|
+
};
|
3604
3742
|
hasRelations = true;
|
3605
3743
|
}
|
3606
3744
|
break;
|
3607
3745
|
}
|
3608
3746
|
case "dynamiczone": {
|
3609
|
-
const
|
3610
|
-
const { populate:
|
3611
|
-
if (
|
3747
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
3748
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
3749
|
+
if (componentHasRelations) {
|
3612
3750
|
hasRelations = true;
|
3613
|
-
return
|
3751
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3614
3752
|
}
|
3615
3753
|
return acc;
|
3616
3754
|
}, {});
|
3617
|
-
if (!isEmpty(
|
3618
|
-
populateAcc[attributeName] = {
|
3755
|
+
if (!isEmpty(dzPopulateFragment)) {
|
3756
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3619
3757
|
}
|
3620
3758
|
break;
|
3621
3759
|
}
|
@@ -3807,41 +3945,70 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3807
3945
|
"updatedBy",
|
3808
3946
|
"status"
|
3809
3947
|
];
|
3810
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
3948
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
3949
|
+
"id",
|
3950
|
+
"locale",
|
3951
|
+
"updatedAt",
|
3952
|
+
"createdAt",
|
3953
|
+
"status",
|
3954
|
+
"publishedAt",
|
3955
|
+
"documentId"
|
3956
|
+
];
|
3811
3957
|
const CONTENT_MANAGER_STATUS = {
|
3812
3958
|
PUBLISHED: "published",
|
3813
3959
|
DRAFT: "draft",
|
3814
3960
|
MODIFIED: "modified"
|
3815
3961
|
};
|
3816
|
-
const
|
3817
|
-
if (!
|
3962
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
3963
|
+
if (!version || !version.updatedAt) {
|
3818
3964
|
return false;
|
3819
3965
|
}
|
3820
|
-
const
|
3821
|
-
const
|
3822
|
-
|
3823
|
-
return difference2 <= threshold;
|
3966
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
3967
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
3968
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3824
3969
|
};
|
3825
3970
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3826
3971
|
/**
|
3827
3972
|
* Returns available locales of a document for the current status
|
3828
3973
|
*/
|
3829
|
-
getAvailableLocales(uid2, version, allVersions) {
|
3974
|
+
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3830
3975
|
const versionsByLocale = groupBy("locale", allVersions);
|
3831
3976
|
delete versionsByLocale[version.locale];
|
3832
|
-
|
3833
|
-
|
3834
|
-
|
3977
|
+
const model = strapi2.getModel(uid2);
|
3978
|
+
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
3979
|
+
const traversalFunction = async (localeVersion) => traverseEntity(
|
3980
|
+
({ key }, { remove }) => {
|
3981
|
+
if (keysToKeep.includes(key)) {
|
3982
|
+
return;
|
3983
|
+
}
|
3984
|
+
remove(key);
|
3985
|
+
},
|
3986
|
+
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
3987
|
+
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
3988
|
+
localeVersion
|
3989
|
+
);
|
3990
|
+
const mappingResult = await async.map(
|
3991
|
+
Object.values(versionsByLocale),
|
3992
|
+
async (localeVersions) => {
|
3993
|
+
const mappedLocaleVersions = await async.map(
|
3994
|
+
localeVersions,
|
3995
|
+
traversalFunction
|
3996
|
+
);
|
3997
|
+
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
3998
|
+
return mappedLocaleVersions[0];
|
3999
|
+
}
|
4000
|
+
const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
|
4001
|
+
const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
|
4002
|
+
if (!draftVersion) {
|
4003
|
+
return;
|
4004
|
+
}
|
4005
|
+
return {
|
4006
|
+
...draftVersion,
|
4007
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4008
|
+
};
|
3835
4009
|
}
|
3836
|
-
|
3837
|
-
|
3838
|
-
if (!draftVersion)
|
3839
|
-
return;
|
3840
|
-
return {
|
3841
|
-
...pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
|
3842
|
-
status: this.getStatus(draftVersion, otherVersions)
|
3843
|
-
};
|
3844
|
-
}).filter(Boolean);
|
4010
|
+
);
|
4011
|
+
return mappingResult.filter(Boolean);
|
3845
4012
|
},
|
3846
4013
|
/**
|
3847
4014
|
* Returns available status of a document for the current locale
|
@@ -3879,26 +4046,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3879
4046
|
});
|
3880
4047
|
},
|
3881
4048
|
getStatus(version, otherDocumentStatuses) {
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
4049
|
+
let draftVersion;
|
4050
|
+
let publishedVersion;
|
4051
|
+
if (version.publishedAt) {
|
4052
|
+
publishedVersion = version;
|
4053
|
+
} else {
|
4054
|
+
draftVersion = version;
|
3885
4055
|
}
|
3886
|
-
|
3887
|
-
|
3888
|
-
|
3889
|
-
|
3890
|
-
|
4056
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4057
|
+
if (otherVersion?.publishedAt) {
|
4058
|
+
publishedVersion = otherVersion;
|
4059
|
+
} else if (otherVersion) {
|
4060
|
+
draftVersion = otherVersion;
|
3891
4061
|
}
|
3892
|
-
if (
|
4062
|
+
if (!draftVersion)
|
3893
4063
|
return CONTENT_MANAGER_STATUS.PUBLISHED;
|
3894
|
-
|
3895
|
-
|
4064
|
+
if (!publishedVersion)
|
4065
|
+
return CONTENT_MANAGER_STATUS.DRAFT;
|
4066
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4067
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3896
4068
|
},
|
4069
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4070
|
+
// We could refactor this so the locales are only loaded when they're
|
4071
|
+
// needed. e.g. in the bulk locale action modal.
|
3897
4072
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4073
|
+
const populate = getValidatableFieldsPopulate(uid2);
|
3898
4074
|
const versions = await strapi2.db.query(uid2).findMany({
|
3899
4075
|
where: { documentId: version.documentId },
|
3900
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
3901
4076
|
populate: {
|
4077
|
+
// Populate only fields that require validation for bulk locale actions
|
4078
|
+
...populate,
|
4079
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3902
4080
|
createdBy: {
|
3903
4081
|
select: ["id", "firstname", "lastname", "email"]
|
3904
4082
|
},
|
@@ -3907,7 +4085,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3907
4085
|
}
|
3908
4086
|
}
|
3909
4087
|
});
|
3910
|
-
const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
|
4088
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
|
3911
4089
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3912
4090
|
return {
|
3913
4091
|
availableLocales: availableLocalesResult,
|
@@ -3920,8 +4098,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3920
4098
|
* - Available status of the document for the current locale
|
3921
4099
|
*/
|
3922
4100
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3923
|
-
if (!document)
|
4101
|
+
if (!document) {
|
3924
4102
|
return document;
|
4103
|
+
}
|
3925
4104
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
3926
4105
|
if (!hasDraftAndPublish) {
|
3927
4106
|
opts.availableStatus = false;
|
@@ -3971,26 +4150,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
3971
4150
|
}, 0);
|
3972
4151
|
};
|
3973
4152
|
const { ApplicationError } = errors;
|
3974
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
3975
4153
|
const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
|
3976
4154
|
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
|
3977
4155
|
const omitIdField = omit("id");
|
3978
|
-
const emitEvent = async (uid2, event, document) => {
|
3979
|
-
const modelDef = strapi.getModel(uid2);
|
3980
|
-
const sanitizedDocument = await sanitize.sanitizers.defaultSanitizeOutput(
|
3981
|
-
{
|
3982
|
-
schema: modelDef,
|
3983
|
-
getModel(uid22) {
|
3984
|
-
return strapi.getModel(uid22);
|
3985
|
-
}
|
3986
|
-
},
|
3987
|
-
document
|
3988
|
-
);
|
3989
|
-
strapi.eventHub.emit(event, {
|
3990
|
-
model: modelDef.modelName,
|
3991
|
-
entry: sanitizedDocument
|
3992
|
-
});
|
3993
|
-
};
|
3994
4156
|
const documentManager = ({ strapi: strapi2 }) => {
|
3995
4157
|
return {
|
3996
4158
|
async findOne(id, uid2, opts = {}) {
|
@@ -4009,6 +4171,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4009
4171
|
} else if (opts.locale && opts.locale !== "*") {
|
4010
4172
|
where.locale = opts.locale;
|
4011
4173
|
}
|
4174
|
+
if (typeof opts.isPublished === "boolean") {
|
4175
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4176
|
+
}
|
4012
4177
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4013
4178
|
},
|
4014
4179
|
async findMany(opts, uid2) {
|
@@ -4016,20 +4181,16 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4016
4181
|
return strapi2.documents(uid2).findMany(params);
|
4017
4182
|
},
|
4018
4183
|
async findPage(opts, uid2) {
|
4019
|
-
const
|
4020
|
-
|
4184
|
+
const params = pagination.withDefaultPagination(opts || {}, {
|
4185
|
+
maxLimit: 1e3
|
4186
|
+
});
|
4021
4187
|
const [documents, total = 0] = await Promise.all([
|
4022
|
-
strapi2.documents(uid2).findMany(
|
4023
|
-
strapi2.documents(uid2).count(
|
4188
|
+
strapi2.documents(uid2).findMany(params),
|
4189
|
+
strapi2.documents(uid2).count(params)
|
4024
4190
|
]);
|
4025
4191
|
return {
|
4026
4192
|
results: documents,
|
4027
|
-
pagination:
|
4028
|
-
page,
|
4029
|
-
pageSize,
|
4030
|
-
pageCount: Math.ceil(total / pageSize),
|
4031
|
-
total
|
4032
|
-
}
|
4193
|
+
pagination: pagination.transformPagedPaginationInfo(params, total)
|
4033
4194
|
};
|
4034
4195
|
},
|
4035
4196
|
async create(uid2, opts = {}) {
|
@@ -4075,70 +4236,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4075
4236
|
return {};
|
4076
4237
|
},
|
4077
4238
|
// FIXME: handle relations
|
4078
|
-
async deleteMany(
|
4079
|
-
const
|
4080
|
-
|
4081
|
-
|
4082
|
-
}
|
4083
|
-
return { count: docs.length };
|
4239
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4240
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4241
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4242
|
+
});
|
4243
|
+
return { count: deletedEntries.length };
|
4084
4244
|
},
|
4085
4245
|
async publish(id, uid2, opts = {}) {
|
4086
4246
|
const populate = await buildDeepPopulate(uid2);
|
4087
4247
|
const params = { ...opts, populate };
|
4088
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4248
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4089
4249
|
},
|
4090
|
-
async publishMany(
|
4091
|
-
|
4092
|
-
|
4093
|
-
|
4094
|
-
|
4095
|
-
|
4096
|
-
|
4097
|
-
strapi2.getModel(uid2),
|
4098
|
-
document,
|
4099
|
-
void 0,
|
4100
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4101
|
-
document
|
4102
|
-
);
|
4103
|
-
})
|
4104
|
-
);
|
4105
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4106
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4107
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4108
|
-
const populate = await buildDeepPopulate(uid2);
|
4109
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4110
|
-
where: filters,
|
4111
|
-
data
|
4112
|
-
});
|
4113
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4114
|
-
where: filters,
|
4115
|
-
populate
|
4250
|
+
async publishMany(uid2, documentIds, locale) {
|
4251
|
+
return strapi2.db.transaction(async () => {
|
4252
|
+
const results = await Promise.all(
|
4253
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4254
|
+
);
|
4255
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4256
|
+
return publishedEntitiesCount;
|
4116
4257
|
});
|
4117
|
-
await Promise.all(
|
4118
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4119
|
-
);
|
4120
|
-
return publishedEntitiesCount;
|
4121
4258
|
},
|
4122
|
-
async unpublishMany(
|
4123
|
-
|
4124
|
-
return
|
4125
|
-
|
4126
|
-
|
4127
|
-
|
4128
|
-
|
4129
|
-
const populate = await buildDeepPopulate(uid2);
|
4130
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4131
|
-
where: filters,
|
4132
|
-
data
|
4133
|
-
});
|
4134
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4135
|
-
where: filters,
|
4136
|
-
populate
|
4259
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4260
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4261
|
+
return Promise.all(
|
4262
|
+
documentIds.map(
|
4263
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4264
|
+
)
|
4265
|
+
);
|
4137
4266
|
});
|
4138
|
-
|
4139
|
-
|
4140
|
-
);
|
4141
|
-
return unpublishedEntitiesCount;
|
4267
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4268
|
+
return { count: unpublishedEntitiesCount };
|
4142
4269
|
},
|
4143
4270
|
async unpublish(id, uid2, opts = {}) {
|
4144
4271
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4163,16 +4290,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4163
4290
|
}
|
4164
4291
|
return sumDraftCounts(document, uid2);
|
4165
4292
|
},
|
4166
|
-
async countManyEntriesDraftRelations(
|
4293
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4167
4294
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4168
4295
|
if (!hasRelations) {
|
4169
4296
|
return 0;
|
4170
4297
|
}
|
4298
|
+
let localeFilter = {};
|
4299
|
+
if (locale) {
|
4300
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4301
|
+
}
|
4171
4302
|
const entities = await strapi2.db.query(uid2).findMany({
|
4172
4303
|
populate,
|
4173
4304
|
where: {
|
4174
|
-
|
4175
|
-
...
|
4305
|
+
documentId: { $in: documentIds },
|
4306
|
+
...localeFilter
|
4176
4307
|
}
|
4177
4308
|
});
|
4178
4309
|
const totalNumberDraftRelations = entities.reduce(
|