@strapi/content-manager 0.0.0-experimental.a65a85fdea97faae8679d3ffc5f9d79af61abd26 → 0.0.0-experimental.abc
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--2aLCv-G.mjs → ComponentConfigurationPage-B3yDbeU1.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-B3yDbeU1.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-KXSuLnQD.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-KXSuLnQD.js.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-BQ17--5R.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-BQ17--5R.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs → EditConfigurationPage-D7PrLO8j.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-D7PrLO8j.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs → EditViewPage-B7VgwJaG.mjs} +58 -47
- package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-BgjdnGz2.js} +57 -48
- package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +1 -0
- package/dist/_chunks/{Field-Caef4JjM.js → Field-CdK7ZLmv.js} +1030 -800
- package/dist/_chunks/Field-CdK7ZLmv.js.map +1 -0
- package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-tHCw4lGA.mjs} +981 -750
- package/dist/_chunks/Field-tHCw4lGA.mjs.map +1 -0
- package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-BJxdTv3Q.mjs} +56 -43
- package/dist/_chunks/Form-BJxdTv3Q.mjs.map +1 -0
- package/dist/_chunks/{Form-BzuAjtRq.js → Form-C_0KTVvV.js} +55 -43
- package/dist/_chunks/Form-C_0KTVvV.js.map +1 -0
- package/dist/_chunks/{History-D6sbCJvo.mjs → History-DR2txJLE.mjs} +151 -57
- package/dist/_chunks/History-DR2txJLE.mjs.map +1 -0
- package/dist/_chunks/{History-C17LiyRg.js → History-nuEzM5qm.js} +151 -58
- package/dist/_chunks/History-nuEzM5qm.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-CnB86Psm.js} +70 -61
- package/dist/_chunks/ListConfigurationPage-CnB86Psm.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-voFVtXu6.mjs} +67 -57
- package/dist/_chunks/ListConfigurationPage-voFVtXu6.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-B_GaWgRH.mjs} +95 -106
- package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-SXIXm-RM.js} +100 -111
- package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-BzsQ3hLZ.js} +5 -5
- package/dist/_chunks/NoContentTypePage-BzsQ3hLZ.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-CYiGpsbj.mjs} +7 -7
- package/dist/_chunks/NoContentTypePage-CYiGpsbj.mjs.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-B5baIHal.mjs} +5 -6
- package/dist/_chunks/NoPermissionsPage-B5baIHal.mjs.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-IGkId4C5.js} +4 -5
- package/dist/_chunks/NoPermissionsPage-IGkId4C5.js.map +1 -0
- package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-CIYDdKU-.mjs} +67 -57
- package/dist/_chunks/Relations-CIYDdKU-.mjs.map +1 -0
- package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-Dhuurpx2.js} +71 -62
- package/dist/_chunks/Relations-Dhuurpx2.js.map +1 -0
- package/dist/_chunks/{en-MBPul9Su.mjs → en-BrCTWlZv.mjs} +11 -4
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
- package/dist/_chunks/{en-C-V1_90f.js → en-uOUIxfcQ.js} +11 -4
- package/dist/_chunks/{en-C-V1_90f.js.map → en-uOUIxfcQ.js.map} +1 -1
- package/dist/_chunks/{index-DNVx8ssZ.mjs → index-C9TJPyni.mjs} +1696 -912
- package/dist/_chunks/index-C9TJPyni.mjs.map +1 -0
- package/dist/_chunks/{index-X_2tafck.js → index-CdT0kHZ8.js} +1626 -843
- package/dist/_chunks/index-CdT0kHZ8.js.map +1 -0
- package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-BNqvLR_b.mjs} +45 -28
- package/dist/_chunks/layout-BNqvLR_b.mjs.map +1 -0
- package/dist/_chunks/{layout-dBc7wN7L.js → layout-C6dxWYT7.js} +45 -30
- package/dist/_chunks/layout-C6dxWYT7.js.map +1 -0
- package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-CkKqKw65.mjs} +2 -2
- package/dist/_chunks/{relations-Dx7tMKJN.mjs.map → relations-CkKqKw65.mjs.map} +1 -1
- package/dist/_chunks/{relations-4pHtBrHJ.js → relations-DtFaDnP1.js} +2 -2
- package/dist/_chunks/{relations-4pHtBrHJ.js.map → relations-DtFaDnP1.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/index.d.ts +3 -0
- 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/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -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 +30 -18
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +48 -53
- 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 +602 -426
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +610 -434
- 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/uid.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 +11 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/index.d.ts +1 -1
- package/dist/server/src/history/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.js
CHANGED
@@ -138,40 +138,65 @@ const FIELDS_TO_IGNORE = [
|
|
138
138
|
"strapi_stage",
|
139
139
|
"strapi_assignee"
|
140
140
|
];
|
141
|
-
const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
|
142
|
-
const sanitizedContentTypeSchemaAttributes = fp.omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
|
143
|
-
const reduceDifferenceToAttributesObject = (diffKeys, source) => {
|
144
|
-
return diffKeys.reduce((previousAttributesObject, diffKey) => {
|
145
|
-
previousAttributesObject[diffKey] = source[diffKey];
|
146
|
-
return previousAttributesObject;
|
147
|
-
}, {});
|
148
|
-
};
|
149
|
-
const versionSchemaKeys = Object.keys(versionSchemaAttributes);
|
150
|
-
const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
|
151
|
-
const uniqueToContentType = fp.difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
|
152
|
-
const added = reduceDifferenceToAttributesObject(
|
153
|
-
uniqueToContentType,
|
154
|
-
sanitizedContentTypeSchemaAttributes
|
155
|
-
);
|
156
|
-
const uniqueToVersion = fp.difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
|
157
|
-
const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
|
158
|
-
return { added, removed };
|
159
|
-
};
|
160
141
|
const DEFAULT_RETENTION_DAYS = 90;
|
161
|
-
const
|
162
|
-
const
|
163
|
-
|
164
|
-
|
142
|
+
const createServiceUtils = ({ strapi: strapi2 }) => {
|
143
|
+
const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
|
144
|
+
const sanitizedContentTypeSchemaAttributes = fp.omit(
|
145
|
+
FIELDS_TO_IGNORE,
|
146
|
+
contentTypeSchemaAttributes
|
147
|
+
);
|
148
|
+
const reduceDifferenceToAttributesObject = (diffKeys, source) => {
|
149
|
+
return diffKeys.reduce(
|
150
|
+
(previousAttributesObject, diffKey) => {
|
151
|
+
previousAttributesObject[diffKey] = source[diffKey];
|
152
|
+
return previousAttributesObject;
|
153
|
+
},
|
154
|
+
{}
|
155
|
+
);
|
156
|
+
};
|
157
|
+
const versionSchemaKeys = Object.keys(versionSchemaAttributes);
|
158
|
+
const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
|
159
|
+
const uniqueToContentType = fp.difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
|
160
|
+
const added = reduceDifferenceToAttributesObject(
|
161
|
+
uniqueToContentType,
|
162
|
+
sanitizedContentTypeSchemaAttributes
|
163
|
+
);
|
164
|
+
const uniqueToVersion = fp.difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
|
165
|
+
const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
|
166
|
+
return { added, removed };
|
165
167
|
};
|
166
|
-
const
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
168
|
+
const getRelationRestoreValue = async (versionRelationData, attribute) => {
|
169
|
+
if (Array.isArray(versionRelationData)) {
|
170
|
+
if (versionRelationData.length === 0)
|
171
|
+
return versionRelationData;
|
172
|
+
const existingAndMissingRelations = await Promise.all(
|
173
|
+
versionRelationData.map((relation) => {
|
174
|
+
return strapi2.documents(attribute.target).findOne({
|
175
|
+
documentId: relation.documentId,
|
176
|
+
locale: relation.locale || void 0
|
177
|
+
});
|
178
|
+
})
|
179
|
+
);
|
180
|
+
return existingAndMissingRelations.filter(
|
181
|
+
(relation) => relation !== null
|
182
|
+
);
|
173
183
|
}
|
174
|
-
return
|
184
|
+
return strapi2.documents(attribute.target).findOne({
|
185
|
+
documentId: versionRelationData.documentId,
|
186
|
+
locale: versionRelationData.locale || void 0
|
187
|
+
});
|
188
|
+
};
|
189
|
+
const getMediaRestoreValue = async (versionRelationData, attribute) => {
|
190
|
+
if (attribute.multiple) {
|
191
|
+
const existingAndMissingMedias = await Promise.all(
|
192
|
+
// @ts-expect-error Fix the type definitions so this isn't any
|
193
|
+
versionRelationData.map((media) => {
|
194
|
+
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
|
195
|
+
})
|
196
|
+
);
|
197
|
+
return existingAndMissingMedias.filter((media) => media != null);
|
198
|
+
}
|
199
|
+
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
175
200
|
};
|
176
201
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
177
202
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
@@ -187,25 +212,39 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
187
212
|
{}
|
188
213
|
);
|
189
214
|
};
|
215
|
+
const getRetentionDays = () => {
|
216
|
+
const featureConfig = strapi2.ee.features.get("cms-content-history");
|
217
|
+
const licenseRetentionDays = typeof featureConfig === "object" && featureConfig?.options.retentionDays;
|
218
|
+
const userRetentionDays = strapi2.config.get("admin.history.retentionDays");
|
219
|
+
if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
|
220
|
+
return userRetentionDays;
|
221
|
+
}
|
222
|
+
return Math.min(licenseRetentionDays, DEFAULT_RETENTION_DAYS);
|
223
|
+
};
|
190
224
|
const getVersionStatus = async (contentTypeUid, document) => {
|
191
225
|
const documentMetadataService = strapi2.plugin("content-manager").service("document-metadata");
|
192
226
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
193
227
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
194
228
|
};
|
195
|
-
const getDeepPopulate2 = (uid2) => {
|
229
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
196
230
|
const model = strapi2.getModel(uid2);
|
197
231
|
const attributes = Object.entries(model.attributes);
|
232
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
198
233
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
199
234
|
switch (attribute.type) {
|
200
235
|
case "relation": {
|
236
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
237
|
+
if (isMorphRelation) {
|
238
|
+
break;
|
239
|
+
}
|
201
240
|
const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
|
202
241
|
if (isVisible2) {
|
203
|
-
acc[attributeName] = {
|
242
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
204
243
|
}
|
205
244
|
break;
|
206
245
|
}
|
207
246
|
case "media": {
|
208
|
-
acc[attributeName] = {
|
247
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
209
248
|
break;
|
210
249
|
}
|
211
250
|
case "component": {
|
@@ -228,80 +267,68 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
228
267
|
return acc;
|
229
268
|
}, {});
|
230
269
|
};
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
238
|
-
return next();
|
270
|
+
const buildMediaResponse = async (values) => {
|
271
|
+
return values.slice(0, 25).reduce(
|
272
|
+
async (currentRelationDataPromise, entry) => {
|
273
|
+
const currentRelationData = await currentRelationDataPromise;
|
274
|
+
if (!entry) {
|
275
|
+
return currentRelationData;
|
239
276
|
}
|
240
|
-
|
241
|
-
|
277
|
+
const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
|
278
|
+
if (relatedEntry) {
|
279
|
+
currentRelationData.results.push(relatedEntry);
|
280
|
+
} else {
|
281
|
+
currentRelationData.meta.missingCount += 1;
|
242
282
|
}
|
243
|
-
|
244
|
-
|
245
|
-
|
283
|
+
return currentRelationData;
|
284
|
+
},
|
285
|
+
Promise.resolve({
|
286
|
+
results: [],
|
287
|
+
meta: { missingCount: 0 }
|
288
|
+
})
|
289
|
+
);
|
290
|
+
};
|
291
|
+
const buildRelationReponse = async (values, attributeSchema) => {
|
292
|
+
return values.slice(0, 25).reduce(
|
293
|
+
async (currentRelationDataPromise, entry) => {
|
294
|
+
const currentRelationData = await currentRelationDataPromise;
|
295
|
+
if (!entry) {
|
296
|
+
return currentRelationData;
|
246
297
|
}
|
247
|
-
const
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
documentId: documentContext.documentId,
|
253
|
-
locale,
|
254
|
-
populate: getDeepPopulate2(contentTypeUid)
|
255
|
-
});
|
256
|
-
const status = await getVersionStatus(contentTypeUid, document);
|
257
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
258
|
-
const componentsSchemas = Object.keys(
|
259
|
-
attributesSchema
|
260
|
-
).reduce((currentComponentSchemas, key) => {
|
261
|
-
const fieldSchema = attributesSchema[key];
|
262
|
-
if (fieldSchema.type === "component") {
|
263
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
264
|
-
return {
|
265
|
-
...currentComponentSchemas,
|
266
|
-
[fieldSchema.component]: componentSchema
|
267
|
-
};
|
268
|
-
}
|
269
|
-
return currentComponentSchemas;
|
270
|
-
}, {});
|
271
|
-
await strapi2.db.transaction(async ({ onCommit }) => {
|
272
|
-
onCommit(() => {
|
273
|
-
this.createVersion({
|
274
|
-
contentType: contentTypeUid,
|
275
|
-
data: fp.omit(FIELDS_TO_IGNORE, document),
|
276
|
-
schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
|
277
|
-
componentsSchemas,
|
278
|
-
relatedDocumentId: documentContext.documentId,
|
279
|
-
locale,
|
280
|
-
status
|
281
|
-
});
|
298
|
+
const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
|
299
|
+
if (relatedEntry) {
|
300
|
+
currentRelationData.results.push({
|
301
|
+
...relatedEntry,
|
302
|
+
status: await getVersionStatus(attributeSchema.target, relatedEntry)
|
282
303
|
});
|
283
|
-
}
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
304
|
+
} else {
|
305
|
+
currentRelationData.meta.missingCount += 1;
|
306
|
+
}
|
307
|
+
return currentRelationData;
|
308
|
+
},
|
309
|
+
Promise.resolve({
|
310
|
+
results: [],
|
311
|
+
meta: { missingCount: 0 }
|
312
|
+
})
|
313
|
+
);
|
314
|
+
};
|
315
|
+
return {
|
316
|
+
getSchemaAttributesDiff,
|
317
|
+
getRelationRestoreValue,
|
318
|
+
getMediaRestoreValue,
|
319
|
+
getDefaultLocale,
|
320
|
+
getLocaleDictionary,
|
321
|
+
getRetentionDays,
|
322
|
+
getVersionStatus,
|
323
|
+
getDeepPopulate: getDeepPopulate2,
|
324
|
+
buildMediaResponse,
|
325
|
+
buildRelationReponse
|
326
|
+
};
|
327
|
+
};
|
328
|
+
const createHistoryService = ({ strapi: strapi2 }) => {
|
329
|
+
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
330
|
+
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
331
|
+
return {
|
305
332
|
async createVersion(historyVersionData) {
|
306
333
|
await query.create({
|
307
334
|
data: {
|
@@ -312,7 +339,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
312
339
|
});
|
313
340
|
},
|
314
341
|
async findVersionsPage(params) {
|
315
|
-
const locale = params.query.locale || await getDefaultLocale();
|
342
|
+
const locale = params.query.locale || await serviceUtils.getDefaultLocale();
|
316
343
|
const [{ results, pagination }, localeDictionary] = await Promise.all([
|
317
344
|
query.findPage({
|
318
345
|
...params.query,
|
@@ -326,78 +353,34 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
326
353
|
populate: ["createdBy"],
|
327
354
|
orderBy: [{ createdAt: "desc" }]
|
328
355
|
}),
|
329
|
-
getLocaleDictionary()
|
356
|
+
serviceUtils.getLocaleDictionary()
|
330
357
|
]);
|
331
|
-
const buildRelationReponse = async (values, attributeSchema) => {
|
332
|
-
return values.slice(0, 25).reduce(
|
333
|
-
async (currentRelationDataPromise, entry) => {
|
334
|
-
const currentRelationData = await currentRelationDataPromise;
|
335
|
-
if (!entry) {
|
336
|
-
return currentRelationData;
|
337
|
-
}
|
338
|
-
const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
|
339
|
-
const permissionChecker2 = getService$1("permission-checker").create({
|
340
|
-
userAbility: params.state.userAbility,
|
341
|
-
model: attributeSchema.target
|
342
|
-
});
|
343
|
-
const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
|
344
|
-
if (sanitizedEntry) {
|
345
|
-
currentRelationData.results.push({
|
346
|
-
...sanitizedEntry,
|
347
|
-
status: await getVersionStatus(attributeSchema.target, sanitizedEntry)
|
348
|
-
});
|
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
|
-
const buildMediaResponse = async (values) => {
|
361
|
-
return values.slice(0, 25).reduce(
|
362
|
-
async (currentRelationDataPromise, entry) => {
|
363
|
-
const currentRelationData = await currentRelationDataPromise;
|
364
|
-
if (!entry) {
|
365
|
-
return currentRelationData;
|
366
|
-
}
|
367
|
-
const permissionChecker2 = getService$1("permission-checker").create({
|
368
|
-
userAbility: params.state.userAbility,
|
369
|
-
model: "plugin::upload.file"
|
370
|
-
});
|
371
|
-
const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
|
372
|
-
const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
|
373
|
-
if (sanitizedEntry) {
|
374
|
-
currentRelationData.results.push(sanitizedEntry);
|
375
|
-
} else {
|
376
|
-
currentRelationData.meta.missingCount += 1;
|
377
|
-
}
|
378
|
-
return currentRelationData;
|
379
|
-
},
|
380
|
-
Promise.resolve({
|
381
|
-
results: [],
|
382
|
-
meta: { missingCount: 0 }
|
383
|
-
})
|
384
|
-
);
|
385
|
-
};
|
386
358
|
const populateEntryRelations = async (entry) => {
|
387
359
|
const entryWithRelations = await Object.entries(entry.schema).reduce(
|
388
360
|
async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
|
389
361
|
const attributeValue = entry.data[attributeKey];
|
390
362
|
const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
|
391
363
|
if (attributeSchema.type === "media") {
|
364
|
+
const permissionChecker2 = getService$1("permission-checker").create({
|
365
|
+
userAbility: params.state.userAbility,
|
366
|
+
model: "plugin::upload.file"
|
367
|
+
});
|
368
|
+
const response = await serviceUtils.buildMediaResponse(attributeValues);
|
369
|
+
const sanitizedResults = await Promise.all(
|
370
|
+
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
371
|
+
);
|
392
372
|
return {
|
393
373
|
...await currentDataWithRelations,
|
394
|
-
[attributeKey]:
|
374
|
+
[attributeKey]: {
|
375
|
+
results: sanitizedResults,
|
376
|
+
meta: response.meta
|
377
|
+
}
|
395
378
|
};
|
396
379
|
}
|
397
380
|
if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
|
398
381
|
if (attributeSchema.target === "admin::user") {
|
399
382
|
const adminUsers = await Promise.all(
|
400
|
-
attributeValues.map(
|
383
|
+
attributeValues.map((userToPopulate) => {
|
401
384
|
if (userToPopulate == null) {
|
402
385
|
return null;
|
403
386
|
}
|
@@ -414,9 +397,23 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
414
397
|
[attributeKey]: adminUsers
|
415
398
|
};
|
416
399
|
}
|
400
|
+
const permissionChecker2 = getService$1("permission-checker").create({
|
401
|
+
userAbility: params.state.userAbility,
|
402
|
+
model: attributeSchema.target
|
403
|
+
});
|
404
|
+
const response = await serviceUtils.buildRelationReponse(
|
405
|
+
attributeValues,
|
406
|
+
attributeSchema
|
407
|
+
);
|
408
|
+
const sanitizedResults = await Promise.all(
|
409
|
+
response.results.map((media) => permissionChecker2.sanitizeOutput(media))
|
410
|
+
);
|
417
411
|
return {
|
418
412
|
...await currentDataWithRelations,
|
419
|
-
[attributeKey]:
|
413
|
+
[attributeKey]: {
|
414
|
+
results: sanitizedResults,
|
415
|
+
meta: response.meta
|
416
|
+
}
|
420
417
|
};
|
421
418
|
}
|
422
419
|
return currentDataWithRelations;
|
@@ -431,7 +428,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
431
428
|
...result,
|
432
429
|
data: await populateEntryRelations(result),
|
433
430
|
meta: {
|
434
|
-
unknownAttributes: getSchemaAttributesDiff(
|
431
|
+
unknownAttributes: serviceUtils.getSchemaAttributesDiff(
|
435
432
|
result.schema,
|
436
433
|
strapi2.getModel(params.query.contentType).attributes
|
437
434
|
)
|
@@ -448,7 +445,10 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
448
445
|
async restoreVersion(versionId) {
|
449
446
|
const version = await query.findOne({ where: { id: versionId } });
|
450
447
|
const contentTypeSchemaAttributes = strapi2.getModel(version.contentType).attributes;
|
451
|
-
const schemaDiff = getSchemaAttributesDiff(
|
448
|
+
const schemaDiff = serviceUtils.getSchemaAttributesDiff(
|
449
|
+
version.schema,
|
450
|
+
contentTypeSchemaAttributes
|
451
|
+
);
|
452
452
|
const dataWithoutAddedAttributes = Object.keys(schemaDiff.added).reduce(
|
453
453
|
(currentData, addedKey) => {
|
454
454
|
currentData[addedKey] = null;
|
@@ -461,61 +461,26 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
461
461
|
FIELDS_TO_IGNORE,
|
462
462
|
contentTypeSchemaAttributes
|
463
463
|
);
|
464
|
-
const
|
465
|
-
|
466
|
-
|
467
|
-
const
|
468
|
-
if (
|
464
|
+
const reducer = strapiUtils.async.reduce(Object.entries(sanitizedSchemaAttributes));
|
465
|
+
const dataWithoutMissingRelations = await reducer(
|
466
|
+
async (previousRelationAttributes, [name, attribute]) => {
|
467
|
+
const versionRelationData = version.data[name];
|
468
|
+
if (!versionRelationData) {
|
469
469
|
return previousRelationAttributes;
|
470
470
|
}
|
471
471
|
if (attribute.type === "relation" && // TODO: handle polymorphic relations
|
472
472
|
attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
|
473
|
-
|
474
|
-
|
475
|
-
return previousRelationAttributes;
|
476
|
-
const existingAndMissingRelations = await Promise.all(
|
477
|
-
relationData.map((relation) => {
|
478
|
-
return strapi2.documents(attribute.target).findOne({
|
479
|
-
documentId: relation.documentId,
|
480
|
-
locale: relation.locale || void 0
|
481
|
-
});
|
482
|
-
})
|
483
|
-
);
|
484
|
-
const existingRelations = existingAndMissingRelations.filter(
|
485
|
-
(relation) => relation !== null
|
486
|
-
);
|
487
|
-
previousRelationAttributes[name] = existingRelations;
|
488
|
-
} else {
|
489
|
-
const existingRelation = await strapi2.documents(attribute.target).findOne({
|
490
|
-
documentId: relationData.documentId,
|
491
|
-
locale: relationData.locale || void 0
|
492
|
-
});
|
493
|
-
if (!existingRelation) {
|
494
|
-
previousRelationAttributes[name] = null;
|
495
|
-
}
|
496
|
-
}
|
473
|
+
const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
|
474
|
+
previousRelationAttributes[name] = data2;
|
497
475
|
}
|
498
476
|
if (attribute.type === "media") {
|
499
|
-
|
500
|
-
|
501
|
-
// @ts-expect-error Fix the type definitions so this isn't any
|
502
|
-
relationData.map((media) => {
|
503
|
-
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
|
504
|
-
})
|
505
|
-
);
|
506
|
-
const existingMedias = existingAndMissingMedias.filter((media) => media != null);
|
507
|
-
previousRelationAttributes[name] = existingMedias;
|
508
|
-
} else {
|
509
|
-
const existingMedia = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: version.data[name].id } });
|
510
|
-
if (!existingMedia) {
|
511
|
-
previousRelationAttributes[name] = null;
|
512
|
-
}
|
513
|
-
}
|
477
|
+
const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
|
478
|
+
previousRelationAttributes[name] = data2;
|
514
479
|
}
|
515
480
|
return previousRelationAttributes;
|
516
481
|
},
|
517
482
|
// Clone to avoid mutating the original version data
|
518
|
-
|
483
|
+
structuredClone(dataWithoutAddedAttributes)
|
519
484
|
);
|
520
485
|
const data = fp.omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
|
521
486
|
const restoredDocument = await strapi2.documents(version.contentType).update({
|
@@ -530,8 +495,118 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
530
495
|
}
|
531
496
|
};
|
532
497
|
};
|
498
|
+
const shouldCreateHistoryVersion = (context) => {
|
499
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
500
|
+
return false;
|
501
|
+
}
|
502
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
503
|
+
return false;
|
504
|
+
}
|
505
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
506
|
+
return false;
|
507
|
+
}
|
508
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
509
|
+
return false;
|
510
|
+
}
|
511
|
+
return true;
|
512
|
+
};
|
513
|
+
const getSchemas = (uid2) => {
|
514
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
515
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
516
|
+
(currentComponentSchemas, key) => {
|
517
|
+
const fieldSchema = attributesSchema[key];
|
518
|
+
if (fieldSchema.type === "component") {
|
519
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
520
|
+
return {
|
521
|
+
...currentComponentSchemas,
|
522
|
+
[fieldSchema.component]: componentSchema
|
523
|
+
};
|
524
|
+
}
|
525
|
+
return currentComponentSchemas;
|
526
|
+
},
|
527
|
+
{}
|
528
|
+
);
|
529
|
+
return {
|
530
|
+
schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
|
531
|
+
componentsSchemas
|
532
|
+
};
|
533
|
+
};
|
534
|
+
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
535
|
+
const state = {
|
536
|
+
deleteExpiredJob: null,
|
537
|
+
isInitialized: false
|
538
|
+
};
|
539
|
+
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
540
|
+
return {
|
541
|
+
async bootstrap() {
|
542
|
+
if (state.isInitialized) {
|
543
|
+
return;
|
544
|
+
}
|
545
|
+
strapi2.documents.use(async (context, next) => {
|
546
|
+
const result = await next();
|
547
|
+
if (!shouldCreateHistoryVersion(context)) {
|
548
|
+
return result;
|
549
|
+
}
|
550
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
551
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
552
|
+
const locales = fp.castArray(context.params?.locale || defaultLocale);
|
553
|
+
if (!locales.length) {
|
554
|
+
return result;
|
555
|
+
}
|
556
|
+
const uid2 = context.contentType.uid;
|
557
|
+
const schemas = getSchemas(uid2);
|
558
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
559
|
+
where: {
|
560
|
+
documentId,
|
561
|
+
locale: { $in: locales },
|
562
|
+
publishedAt: null
|
563
|
+
},
|
564
|
+
populate: serviceUtils.getDeepPopulate(
|
565
|
+
uid2,
|
566
|
+
true
|
567
|
+
/* use database syntax */
|
568
|
+
)
|
569
|
+
});
|
570
|
+
await strapi2.db.transaction(async ({ onCommit }) => {
|
571
|
+
onCommit(async () => {
|
572
|
+
for (const entry of localeEntries) {
|
573
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
574
|
+
await getService(strapi2, "history").createVersion({
|
575
|
+
contentType: uid2,
|
576
|
+
data: fp.omit(FIELDS_TO_IGNORE, entry),
|
577
|
+
relatedDocumentId: documentId,
|
578
|
+
locale: entry.locale,
|
579
|
+
status,
|
580
|
+
...schemas
|
581
|
+
});
|
582
|
+
}
|
583
|
+
});
|
584
|
+
});
|
585
|
+
return result;
|
586
|
+
});
|
587
|
+
state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
|
588
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
589
|
+
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
590
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
591
|
+
where: {
|
592
|
+
created_at: {
|
593
|
+
$lt: expirationDate.toISOString()
|
594
|
+
}
|
595
|
+
}
|
596
|
+
});
|
597
|
+
});
|
598
|
+
state.isInitialized = true;
|
599
|
+
},
|
600
|
+
async destroy() {
|
601
|
+
if (state.deleteExpiredJob) {
|
602
|
+
state.deleteExpiredJob.cancel();
|
603
|
+
}
|
604
|
+
}
|
605
|
+
};
|
606
|
+
};
|
533
607
|
const services$1 = {
|
534
|
-
history: createHistoryService
|
608
|
+
history: createHistoryService,
|
609
|
+
lifecycles: createLifecyclesService
|
535
610
|
};
|
536
611
|
const info = { pluginName: "content-manager", type: "admin" };
|
537
612
|
const historyVersionRouter = {
|
@@ -611,10 +686,10 @@ const getFeature = () => {
|
|
611
686
|
strapi2.get("models").add(historyVersion);
|
612
687
|
},
|
613
688
|
bootstrap({ strapi: strapi2 }) {
|
614
|
-
getService(strapi2, "
|
689
|
+
getService(strapi2, "lifecycles").bootstrap();
|
615
690
|
},
|
616
691
|
destroy({ strapi: strapi2 }) {
|
617
|
-
getService(strapi2, "
|
692
|
+
getService(strapi2, "lifecycles").destroy();
|
618
693
|
},
|
619
694
|
controllers: controllers$1,
|
620
695
|
services: services$1,
|
@@ -1433,7 +1508,7 @@ const { PaginationError, ValidationError } = strapiUtils.errors;
|
|
1433
1508
|
const TYPES = ["singleType", "collectionType"];
|
1434
1509
|
const kindSchema = strapiUtils.yup.string().oneOf(TYPES).nullable();
|
1435
1510
|
const bulkActionInputSchema = strapiUtils.yup.object({
|
1436
|
-
|
1511
|
+
documentIds: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
|
1437
1512
|
}).required();
|
1438
1513
|
const generateUIDInputSchema = strapiUtils.yup.object({
|
1439
1514
|
contentTypeUID: strapiUtils.yup.string().required(),
|
@@ -1532,15 +1607,49 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1532
1607
|
}
|
1533
1608
|
}, body);
|
1534
1609
|
};
|
1535
|
-
const
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1610
|
+
const singleLocaleSchema = strapiUtils.yup.string().nullable();
|
1611
|
+
const multipleLocaleSchema = strapiUtils.yup.lazy(
|
1612
|
+
(value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1613
|
+
);
|
1614
|
+
const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
|
1615
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1616
|
+
const { allowMultipleLocales } = opts;
|
1617
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1618
|
+
const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1619
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1620
|
+
const schema = strapiUtils.yup.object().shape({
|
1621
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1622
|
+
status: statusSchema
|
1623
|
+
});
|
1624
|
+
try {
|
1625
|
+
await strapiUtils.validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1626
|
+
return { locale, status, ...rest };
|
1627
|
+
} catch (error) {
|
1628
|
+
throw new strapiUtils.errors.ValidationError(`Validation error: ${error.message}`);
|
1542
1629
|
}
|
1543
|
-
|
1630
|
+
};
|
1631
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1632
|
+
const documentMetadata2 = getService$1("document-metadata");
|
1633
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1634
|
+
let {
|
1635
|
+
meta: { availableLocales, availableStatus }
|
1636
|
+
} = serviceOutput;
|
1637
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1638
|
+
availableLocales = await strapiUtils.async.map(
|
1639
|
+
availableLocales,
|
1640
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1641
|
+
);
|
1642
|
+
availableStatus = await strapiUtils.async.map(
|
1643
|
+
availableStatus,
|
1644
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1645
|
+
);
|
1646
|
+
return {
|
1647
|
+
...serviceOutput,
|
1648
|
+
meta: {
|
1649
|
+
availableLocales,
|
1650
|
+
availableStatus
|
1651
|
+
}
|
1652
|
+
};
|
1544
1653
|
};
|
1545
1654
|
const createDocument = async (ctx, opts) => {
|
1546
1655
|
const { userAbility, user } = ctx.state;
|
@@ -1555,7 +1664,7 @@ const createDocument = async (ctx, opts) => {
|
|
1555
1664
|
const setCreator = strapiUtils.setCreatorFields({ user });
|
1556
1665
|
const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
|
1557
1666
|
const sanitizedBody = await sanitizeFn(body);
|
1558
|
-
const { locale, status
|
1667
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1559
1668
|
return documentManager2.create(model, {
|
1560
1669
|
data: sanitizedBody,
|
1561
1670
|
locale,
|
@@ -1574,7 +1683,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1574
1683
|
}
|
1575
1684
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1576
1685
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1577
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1686
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1578
1687
|
const [documentVersion, documentExists] = await Promise.all([
|
1579
1688
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1580
1689
|
documentManager2.exists(model, id)
|
@@ -1612,7 +1721,7 @@ const collectionTypes = {
|
|
1612
1721
|
}
|
1613
1722
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1614
1723
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1615
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
1724
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1616
1725
|
const { results: documents, pagination } = await documentManager2.findPage(
|
1617
1726
|
{ ...permissionQuery, populate, locale, status },
|
1618
1727
|
model
|
@@ -1641,14 +1750,13 @@ const collectionTypes = {
|
|
1641
1750
|
const { userAbility } = ctx.state;
|
1642
1751
|
const { model, id } = ctx.params;
|
1643
1752
|
const documentManager2 = getService$1("document-manager");
|
1644
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1645
1753
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1646
1754
|
if (permissionChecker2.cannot.read()) {
|
1647
1755
|
return ctx.forbidden();
|
1648
1756
|
}
|
1649
1757
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1650
1758
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1651
|
-
const { locale, status
|
1759
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1652
1760
|
const version = await documentManager2.findOne(id, model, {
|
1653
1761
|
populate,
|
1654
1762
|
locale,
|
@@ -1659,8 +1767,10 @@ const collectionTypes = {
|
|
1659
1767
|
if (!exists) {
|
1660
1768
|
return ctx.notFound();
|
1661
1769
|
}
|
1662
|
-
const { meta } = await
|
1770
|
+
const { meta } = await formatDocumentWithMetadata(
|
1771
|
+
permissionChecker2,
|
1663
1772
|
model,
|
1773
|
+
// @ts-expect-error TODO: fix
|
1664
1774
|
{ id, locale, publishedAt: null },
|
1665
1775
|
{ availableLocales: true, availableStatus: false }
|
1666
1776
|
);
|
@@ -1671,12 +1781,11 @@ const collectionTypes = {
|
|
1671
1781
|
return ctx.forbidden();
|
1672
1782
|
}
|
1673
1783
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1674
|
-
ctx.body = await
|
1784
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1675
1785
|
},
|
1676
1786
|
async create(ctx) {
|
1677
1787
|
const { userAbility } = ctx.state;
|
1678
1788
|
const { model } = ctx.params;
|
1679
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1680
1789
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1681
1790
|
const [totalEntries, document] = await Promise.all([
|
1682
1791
|
strapi.db.query(model).count(),
|
@@ -1684,7 +1793,7 @@ const collectionTypes = {
|
|
1684
1793
|
]);
|
1685
1794
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1686
1795
|
ctx.status = 201;
|
1687
|
-
ctx.body = await
|
1796
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1688
1797
|
// Empty metadata as it's not relevant for a new document
|
1689
1798
|
availableLocales: false,
|
1690
1799
|
availableStatus: false
|
@@ -1698,25 +1807,23 @@ const collectionTypes = {
|
|
1698
1807
|
async update(ctx) {
|
1699
1808
|
const { userAbility } = ctx.state;
|
1700
1809
|
const { model } = ctx.params;
|
1701
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1702
1810
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1703
1811
|
const updatedVersion = await updateDocument(ctx);
|
1704
1812
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1705
|
-
ctx.body = await
|
1813
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1706
1814
|
},
|
1707
1815
|
async clone(ctx) {
|
1708
1816
|
const { userAbility, user } = ctx.state;
|
1709
1817
|
const { model, sourceId: id } = ctx.params;
|
1710
1818
|
const { body } = ctx.request;
|
1711
1819
|
const documentManager2 = getService$1("document-manager");
|
1712
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1713
1820
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1714
1821
|
if (permissionChecker2.cannot.create()) {
|
1715
1822
|
return ctx.forbidden();
|
1716
1823
|
}
|
1717
1824
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1718
1825
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1719
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1826
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1720
1827
|
const document = await documentManager2.findOne(id, model, {
|
1721
1828
|
populate,
|
1722
1829
|
locale,
|
@@ -1732,7 +1839,7 @@ const collectionTypes = {
|
|
1732
1839
|
const sanitizedBody = await sanitizeFn(body);
|
1733
1840
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1734
1841
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1735
|
-
ctx.body = await
|
1842
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1736
1843
|
// Empty metadata as it's not relevant for a new document
|
1737
1844
|
availableLocales: false,
|
1738
1845
|
availableStatus: false
|
@@ -1761,7 +1868,7 @@ const collectionTypes = {
|
|
1761
1868
|
}
|
1762
1869
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1763
1870
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1764
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
1871
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1765
1872
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1766
1873
|
if (documentLocales.length === 0) {
|
1767
1874
|
return ctx.notFound();
|
@@ -1783,7 +1890,6 @@ const collectionTypes = {
|
|
1783
1890
|
const { id, model } = ctx.params;
|
1784
1891
|
const { body } = ctx.request;
|
1785
1892
|
const documentManager2 = getService$1("document-manager");
|
1786
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1787
1893
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1788
1894
|
if (permissionChecker2.cannot.publish()) {
|
1789
1895
|
return ctx.forbidden();
|
@@ -1791,25 +1897,46 @@ const collectionTypes = {
|
|
1791
1897
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1792
1898
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1793
1899
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1794
|
-
|
1900
|
+
let document;
|
1901
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1902
|
+
const isCreate = fp.isNil(id);
|
1903
|
+
if (isCreate) {
|
1904
|
+
if (permissionChecker2.cannot.create()) {
|
1905
|
+
throw new strapiUtils.errors.ForbiddenError();
|
1906
|
+
}
|
1907
|
+
document = await createDocument(ctx, { populate });
|
1908
|
+
}
|
1909
|
+
const isUpdate = !isCreate;
|
1910
|
+
if (isUpdate) {
|
1911
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
1912
|
+
if (!document) {
|
1913
|
+
throw new strapiUtils.errors.NotFoundError("Document not found");
|
1914
|
+
}
|
1915
|
+
if (permissionChecker2.can.update(document)) {
|
1916
|
+
await updateDocument(ctx);
|
1917
|
+
}
|
1918
|
+
}
|
1795
1919
|
if (permissionChecker2.cannot.publish(document)) {
|
1796
1920
|
throw new strapiUtils.errors.ForbiddenError();
|
1797
1921
|
}
|
1798
|
-
const
|
1799
|
-
return documentManager2.publish(document.documentId, model, {
|
1922
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1800
1923
|
locale
|
1801
1924
|
// TODO: Allow setting creator fields on publish
|
1802
1925
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1803
1926
|
});
|
1927
|
+
if (!publishResult || publishResult.length === 0) {
|
1928
|
+
throw new strapiUtils.errors.NotFoundError("Document not found or already published.");
|
1929
|
+
}
|
1930
|
+
return publishResult[0];
|
1804
1931
|
});
|
1805
1932
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1806
|
-
ctx.body = await
|
1933
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1807
1934
|
},
|
1808
1935
|
async bulkPublish(ctx) {
|
1809
1936
|
const { userAbility } = ctx.state;
|
1810
1937
|
const { model } = ctx.params;
|
1811
1938
|
const { body } = ctx.request;
|
1812
|
-
const {
|
1939
|
+
const { documentIds } = body;
|
1813
1940
|
await validateBulkActionInput(body);
|
1814
1941
|
const documentManager2 = getService$1("document-manager");
|
1815
1942
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1818,8 +1945,13 @@ const collectionTypes = {
|
|
1818
1945
|
}
|
1819
1946
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1820
1947
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1821
|
-
const
|
1822
|
-
|
1948
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1949
|
+
allowMultipleLocales: true
|
1950
|
+
});
|
1951
|
+
const entityPromises = documentIds.map(
|
1952
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1953
|
+
);
|
1954
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1823
1955
|
for (const entity of entities) {
|
1824
1956
|
if (!entity) {
|
1825
1957
|
return ctx.notFound();
|
@@ -1828,24 +1960,25 @@ const collectionTypes = {
|
|
1828
1960
|
return ctx.forbidden();
|
1829
1961
|
}
|
1830
1962
|
}
|
1831
|
-
const
|
1963
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1832
1964
|
ctx.body = { count };
|
1833
1965
|
},
|
1834
1966
|
async bulkUnpublish(ctx) {
|
1835
1967
|
const { userAbility } = ctx.state;
|
1836
1968
|
const { model } = ctx.params;
|
1837
1969
|
const { body } = ctx.request;
|
1838
|
-
const {
|
1970
|
+
const { documentIds } = body;
|
1839
1971
|
await validateBulkActionInput(body);
|
1840
1972
|
const documentManager2 = getService$1("document-manager");
|
1841
1973
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1842
1974
|
if (permissionChecker2.cannot.unpublish()) {
|
1843
1975
|
return ctx.forbidden();
|
1844
1976
|
}
|
1845
|
-
const
|
1846
|
-
const
|
1847
|
-
|
1848
|
-
|
1977
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1978
|
+
const entityPromises = documentIds.map(
|
1979
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1980
|
+
);
|
1981
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1849
1982
|
for (const entity of entities) {
|
1850
1983
|
if (!entity) {
|
1851
1984
|
return ctx.notFound();
|
@@ -1854,7 +1987,8 @@ const collectionTypes = {
|
|
1854
1987
|
return ctx.forbidden();
|
1855
1988
|
}
|
1856
1989
|
}
|
1857
|
-
const
|
1990
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
1991
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1858
1992
|
ctx.body = { count };
|
1859
1993
|
},
|
1860
1994
|
async unpublish(ctx) {
|
@@ -1864,7 +1998,6 @@ const collectionTypes = {
|
|
1864
1998
|
body: { discardDraft, ...body }
|
1865
1999
|
} = ctx.request;
|
1866
2000
|
const documentManager2 = getService$1("document-manager");
|
1867
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1868
2001
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1869
2002
|
if (permissionChecker2.cannot.unpublish()) {
|
1870
2003
|
return ctx.forbidden();
|
@@ -1874,7 +2007,7 @@ const collectionTypes = {
|
|
1874
2007
|
}
|
1875
2008
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1876
2009
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1877
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2010
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1878
2011
|
const document = await documentManager2.findOne(id, model, {
|
1879
2012
|
populate,
|
1880
2013
|
locale,
|
@@ -1896,7 +2029,7 @@ const collectionTypes = {
|
|
1896
2029
|
ctx.body = await strapiUtils.async.pipe(
|
1897
2030
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1898
2031
|
permissionChecker2.sanitizeOutput,
|
1899
|
-
(document2) =>
|
2032
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1900
2033
|
)(document);
|
1901
2034
|
});
|
1902
2035
|
},
|
@@ -1905,14 +2038,13 @@ const collectionTypes = {
|
|
1905
2038
|
const { id, model } = ctx.params;
|
1906
2039
|
const { body } = ctx.request;
|
1907
2040
|
const documentManager2 = getService$1("document-manager");
|
1908
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1909
2041
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1910
2042
|
if (permissionChecker2.cannot.discard()) {
|
1911
2043
|
return ctx.forbidden();
|
1912
2044
|
}
|
1913
2045
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1914
2046
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1915
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2047
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1916
2048
|
const document = await documentManager2.findOne(id, model, {
|
1917
2049
|
populate,
|
1918
2050
|
locale,
|
@@ -1927,14 +2059,14 @@ const collectionTypes = {
|
|
1927
2059
|
ctx.body = await strapiUtils.async.pipe(
|
1928
2060
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1929
2061
|
permissionChecker2.sanitizeOutput,
|
1930
|
-
(document2) =>
|
2062
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1931
2063
|
)(document);
|
1932
2064
|
},
|
1933
2065
|
async bulkDelete(ctx) {
|
1934
2066
|
const { userAbility } = ctx.state;
|
1935
2067
|
const { model } = ctx.params;
|
1936
2068
|
const { query, body } = ctx.request;
|
1937
|
-
const {
|
2069
|
+
const { documentIds } = body;
|
1938
2070
|
await validateBulkActionInput(body);
|
1939
2071
|
const documentManager2 = getService$1("document-manager");
|
1940
2072
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1942,14 +2074,22 @@ const collectionTypes = {
|
|
1942
2074
|
return ctx.forbidden();
|
1943
2075
|
}
|
1944
2076
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1945
|
-
const
|
1946
|
-
const
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
2077
|
+
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2078
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2079
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2080
|
+
populate,
|
2081
|
+
locale
|
2082
|
+
});
|
2083
|
+
if (documentLocales.length === 0) {
|
2084
|
+
return ctx.notFound();
|
2085
|
+
}
|
2086
|
+
for (const document of documentLocales) {
|
2087
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2088
|
+
return ctx.forbidden();
|
1950
2089
|
}
|
1951
|
-
}
|
1952
|
-
const
|
2090
|
+
}
|
2091
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2092
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1953
2093
|
ctx.body = { count };
|
1954
2094
|
},
|
1955
2095
|
async countDraftRelations(ctx) {
|
@@ -1962,7 +2102,7 @@ const collectionTypes = {
|
|
1962
2102
|
}
|
1963
2103
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1964
2104
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1965
|
-
const { locale, status
|
2105
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1966
2106
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
1967
2107
|
if (!entity) {
|
1968
2108
|
return ctx.notFound();
|
@@ -1977,7 +2117,7 @@ const collectionTypes = {
|
|
1977
2117
|
},
|
1978
2118
|
async countManyEntriesDraftRelations(ctx) {
|
1979
2119
|
const { userAbility } = ctx.state;
|
1980
|
-
const ids = ctx.request.query.
|
2120
|
+
const ids = ctx.request.query.documentIds;
|
1981
2121
|
const locale = ctx.request.query.locale;
|
1982
2122
|
const { model } = ctx.params;
|
1983
2123
|
const documentManager2 = getService$1("document-manager");
|
@@ -1985,16 +2125,16 @@ const collectionTypes = {
|
|
1985
2125
|
if (permissionChecker2.cannot.read()) {
|
1986
2126
|
return ctx.forbidden();
|
1987
2127
|
}
|
1988
|
-
const
|
2128
|
+
const documents = await documentManager2.findMany(
|
1989
2129
|
{
|
1990
2130
|
filters: {
|
1991
|
-
|
2131
|
+
documentId: ids
|
1992
2132
|
},
|
1993
2133
|
locale
|
1994
2134
|
},
|
1995
2135
|
model
|
1996
2136
|
);
|
1997
|
-
if (!
|
2137
|
+
if (!documents) {
|
1998
2138
|
return ctx.notFound();
|
1999
2139
|
}
|
2000
2140
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2490,7 +2630,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2490
2630
|
throw new strapiUtils.errors.ForbiddenError();
|
2491
2631
|
}
|
2492
2632
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2493
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2633
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2494
2634
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2495
2635
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2496
2636
|
// Find the first document to check if it exists
|
@@ -2527,12 +2667,11 @@ const singleTypes = {
|
|
2527
2667
|
const { model } = ctx.params;
|
2528
2668
|
const { query = {} } = ctx.request;
|
2529
2669
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2530
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2531
2670
|
if (permissionChecker2.cannot.read()) {
|
2532
2671
|
return ctx.forbidden();
|
2533
2672
|
}
|
2534
2673
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2535
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2674
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2536
2675
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2537
2676
|
if (!version) {
|
2538
2677
|
if (permissionChecker2.cannot.create()) {
|
@@ -2542,8 +2681,10 @@ const singleTypes = {
|
|
2542
2681
|
if (!document) {
|
2543
2682
|
return ctx.notFound();
|
2544
2683
|
}
|
2545
|
-
const { meta } = await
|
2684
|
+
const { meta } = await formatDocumentWithMetadata(
|
2685
|
+
permissionChecker2,
|
2546
2686
|
model,
|
2687
|
+
// @ts-expect-error - fix types
|
2547
2688
|
{ id: document.documentId, locale, publishedAt: null },
|
2548
2689
|
{ availableLocales: true, availableStatus: false }
|
2549
2690
|
);
|
@@ -2554,16 +2695,15 @@ const singleTypes = {
|
|
2554
2695
|
return ctx.forbidden();
|
2555
2696
|
}
|
2556
2697
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2557
|
-
ctx.body = await
|
2698
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2558
2699
|
},
|
2559
2700
|
async createOrUpdate(ctx) {
|
2560
2701
|
const { userAbility } = ctx.state;
|
2561
2702
|
const { model } = ctx.params;
|
2562
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2563
2703
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2564
2704
|
const document = await createOrUpdateDocument(ctx);
|
2565
2705
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2566
|
-
ctx.body = await
|
2706
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2567
2707
|
},
|
2568
2708
|
async delete(ctx) {
|
2569
2709
|
const { userAbility } = ctx.state;
|
@@ -2576,7 +2716,7 @@ const singleTypes = {
|
|
2576
2716
|
}
|
2577
2717
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2578
2718
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2579
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2719
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2580
2720
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2581
2721
|
populate,
|
2582
2722
|
locale
|
@@ -2599,7 +2739,6 @@ const singleTypes = {
|
|
2599
2739
|
const { model } = ctx.params;
|
2600
2740
|
const { query = {} } = ctx.request;
|
2601
2741
|
const documentManager2 = getService$1("document-manager");
|
2602
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2603
2742
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2604
2743
|
if (permissionChecker2.cannot.publish()) {
|
2605
2744
|
return ctx.forbidden();
|
@@ -2614,11 +2753,12 @@ const singleTypes = {
|
|
2614
2753
|
if (permissionChecker2.cannot.publish(document)) {
|
2615
2754
|
throw new strapiUtils.errors.ForbiddenError();
|
2616
2755
|
}
|
2617
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2618
|
-
|
2756
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2757
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2758
|
+
return publishResult.at(0);
|
2619
2759
|
});
|
2620
2760
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2621
|
-
ctx.body = await
|
2761
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2622
2762
|
},
|
2623
2763
|
async unpublish(ctx) {
|
2624
2764
|
const { userAbility } = ctx.state;
|
@@ -2628,7 +2768,6 @@ const singleTypes = {
|
|
2628
2768
|
query = {}
|
2629
2769
|
} = ctx.request;
|
2630
2770
|
const documentManager2 = getService$1("document-manager");
|
2631
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2632
2771
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2633
2772
|
if (permissionChecker2.cannot.unpublish()) {
|
2634
2773
|
return ctx.forbidden();
|
@@ -2637,7 +2776,7 @@ const singleTypes = {
|
|
2637
2776
|
return ctx.forbidden();
|
2638
2777
|
}
|
2639
2778
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2640
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2779
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2641
2780
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2642
2781
|
if (!document) {
|
2643
2782
|
return ctx.notFound();
|
@@ -2655,7 +2794,7 @@ const singleTypes = {
|
|
2655
2794
|
ctx.body = await strapiUtils.async.pipe(
|
2656
2795
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2657
2796
|
permissionChecker2.sanitizeOutput,
|
2658
|
-
(document2) =>
|
2797
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2659
2798
|
)(document);
|
2660
2799
|
});
|
2661
2800
|
},
|
@@ -2664,13 +2803,12 @@ const singleTypes = {
|
|
2664
2803
|
const { model } = ctx.params;
|
2665
2804
|
const { body, query = {} } = ctx.request;
|
2666
2805
|
const documentManager2 = getService$1("document-manager");
|
2667
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2668
2806
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2669
2807
|
if (permissionChecker2.cannot.discard()) {
|
2670
2808
|
return ctx.forbidden();
|
2671
2809
|
}
|
2672
2810
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2673
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2811
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2674
2812
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2675
2813
|
if (!document) {
|
2676
2814
|
return ctx.notFound();
|
@@ -2681,7 +2819,7 @@ const singleTypes = {
|
|
2681
2819
|
ctx.body = await strapiUtils.async.pipe(
|
2682
2820
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2683
2821
|
permissionChecker2.sanitizeOutput,
|
2684
|
-
(document2) =>
|
2822
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2685
2823
|
)(document);
|
2686
2824
|
},
|
2687
2825
|
async countDraftRelations(ctx) {
|
@@ -2690,7 +2828,7 @@ const singleTypes = {
|
|
2690
2828
|
const { query } = ctx.request;
|
2691
2829
|
const documentManager2 = getService$1("document-manager");
|
2692
2830
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2693
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2831
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2694
2832
|
if (permissionChecker2.cannot.read()) {
|
2695
2833
|
return ctx.forbidden();
|
2696
2834
|
}
|
@@ -2711,7 +2849,7 @@ const uid$1 = {
|
|
2711
2849
|
async generateUID(ctx) {
|
2712
2850
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2713
2851
|
const { query = {} } = ctx.request;
|
2714
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2852
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2715
2853
|
await validateUIDField(contentTypeUID, field);
|
2716
2854
|
const uidService = getService$1("uid");
|
2717
2855
|
ctx.body = {
|
@@ -2723,7 +2861,7 @@ const uid$1 = {
|
|
2723
2861
|
ctx.request.body
|
2724
2862
|
);
|
2725
2863
|
const { query = {} } = ctx.request;
|
2726
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2864
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2727
2865
|
await validateUIDField(contentTypeUID, field);
|
2728
2866
|
const uidService = getService$1("uid");
|
2729
2867
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -3514,7 +3652,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3514
3652
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3515
3653
|
}
|
3516
3654
|
});
|
3517
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils__default.default.contentTypes;
|
3655
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils__default.default.contentTypes;
|
3518
3656
|
const { isAnyToMany } = strapiUtils__default.default.relations;
|
3519
3657
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils__default.default.contentTypes.constants;
|
3520
3658
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3605,6 +3743,42 @@ const getDeepPopulate = (uid2, {
|
|
3605
3743
|
{}
|
3606
3744
|
);
|
3607
3745
|
};
|
3746
|
+
const getValidatableFieldsPopulate = (uid2, {
|
3747
|
+
initialPopulate = {},
|
3748
|
+
countMany = false,
|
3749
|
+
countOne = false,
|
3750
|
+
maxLevel = Infinity
|
3751
|
+
} = {}, level = 1) => {
|
3752
|
+
if (level > maxLevel) {
|
3753
|
+
return {};
|
3754
|
+
}
|
3755
|
+
const model = strapi.getModel(uid2);
|
3756
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3757
|
+
if (!getDoesAttributeRequireValidation(attribute)) {
|
3758
|
+
return populateAcc;
|
3759
|
+
}
|
3760
|
+
if (isScalarAttribute(attribute)) {
|
3761
|
+
return fp.merge(populateAcc, {
|
3762
|
+
[attributeName]: true
|
3763
|
+
});
|
3764
|
+
}
|
3765
|
+
return fp.merge(
|
3766
|
+
populateAcc,
|
3767
|
+
getPopulateFor(
|
3768
|
+
attributeName,
|
3769
|
+
model,
|
3770
|
+
{
|
3771
|
+
// @ts-expect-error - improve types
|
3772
|
+
initialPopulate: initialPopulate?.[attributeName],
|
3773
|
+
countMany,
|
3774
|
+
countOne,
|
3775
|
+
maxLevel
|
3776
|
+
},
|
3777
|
+
level
|
3778
|
+
)
|
3779
|
+
);
|
3780
|
+
}, {});
|
3781
|
+
};
|
3608
3782
|
const getDeepPopulateDraftCount = (uid2) => {
|
3609
3783
|
const model = strapi.getModel(uid2);
|
3610
3784
|
let hasRelations = false;
|
@@ -3612,6 +3786,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3612
3786
|
const attribute = model.attributes[attributeName];
|
3613
3787
|
switch (attribute.type) {
|
3614
3788
|
case "relation": {
|
3789
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
3790
|
+
if (isMorphRelation) {
|
3791
|
+
break;
|
3792
|
+
}
|
3615
3793
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3616
3794
|
populateAcc[attributeName] = {
|
3617
3795
|
count: true,
|
@@ -3626,22 +3804,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3626
3804
|
attribute.component
|
3627
3805
|
);
|
3628
3806
|
if (childHasRelations) {
|
3629
|
-
populateAcc[attributeName] = {
|
3807
|
+
populateAcc[attributeName] = {
|
3808
|
+
populate: populate2
|
3809
|
+
};
|
3630
3810
|
hasRelations = true;
|
3631
3811
|
}
|
3632
3812
|
break;
|
3633
3813
|
}
|
3634
3814
|
case "dynamiczone": {
|
3635
|
-
const
|
3636
|
-
const { populate:
|
3637
|
-
if (
|
3815
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
3816
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
3817
|
+
if (componentHasRelations) {
|
3638
3818
|
hasRelations = true;
|
3639
|
-
return
|
3819
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3640
3820
|
}
|
3641
3821
|
return acc;
|
3642
3822
|
}, {});
|
3643
|
-
if (!fp.isEmpty(
|
3644
|
-
populateAcc[attributeName] = {
|
3823
|
+
if (!fp.isEmpty(dzPopulateFragment)) {
|
3824
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3645
3825
|
}
|
3646
3826
|
break;
|
3647
3827
|
}
|
@@ -3833,41 +4013,70 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3833
4013
|
"updatedBy",
|
3834
4014
|
"status"
|
3835
4015
|
];
|
3836
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
4016
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
4017
|
+
"id",
|
4018
|
+
"locale",
|
4019
|
+
"updatedAt",
|
4020
|
+
"createdAt",
|
4021
|
+
"status",
|
4022
|
+
"publishedAt",
|
4023
|
+
"documentId"
|
4024
|
+
];
|
3837
4025
|
const CONTENT_MANAGER_STATUS = {
|
3838
4026
|
PUBLISHED: "published",
|
3839
4027
|
DRAFT: "draft",
|
3840
4028
|
MODIFIED: "modified"
|
3841
4029
|
};
|
3842
|
-
const
|
3843
|
-
if (!
|
4030
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
4031
|
+
if (!version || !version.updatedAt) {
|
3844
4032
|
return false;
|
3845
4033
|
}
|
3846
|
-
const
|
3847
|
-
const
|
3848
|
-
|
3849
|
-
return difference <= threshold;
|
4034
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
4035
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
4036
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3850
4037
|
};
|
3851
4038
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3852
4039
|
/**
|
3853
4040
|
* Returns available locales of a document for the current status
|
3854
4041
|
*/
|
3855
|
-
getAvailableLocales(uid2, version, allVersions) {
|
4042
|
+
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3856
4043
|
const versionsByLocale = fp.groupBy("locale", allVersions);
|
3857
4044
|
delete versionsByLocale[version.locale];
|
3858
|
-
|
3859
|
-
|
3860
|
-
|
4045
|
+
const model = strapi2.getModel(uid2);
|
4046
|
+
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
4047
|
+
const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
|
4048
|
+
({ key }, { remove }) => {
|
4049
|
+
if (keysToKeep.includes(key)) {
|
4050
|
+
return;
|
4051
|
+
}
|
4052
|
+
remove(key);
|
4053
|
+
},
|
4054
|
+
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
4055
|
+
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
4056
|
+
localeVersion
|
4057
|
+
);
|
4058
|
+
const mappingResult = await strapiUtils.async.map(
|
4059
|
+
Object.values(versionsByLocale),
|
4060
|
+
async (localeVersions) => {
|
4061
|
+
const mappedLocaleVersions = await strapiUtils.async.map(
|
4062
|
+
localeVersions,
|
4063
|
+
traversalFunction
|
4064
|
+
);
|
4065
|
+
if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
|
4066
|
+
return mappedLocaleVersions[0];
|
4067
|
+
}
|
4068
|
+
const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
|
4069
|
+
const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
|
4070
|
+
if (!draftVersion) {
|
4071
|
+
return;
|
4072
|
+
}
|
4073
|
+
return {
|
4074
|
+
...draftVersion,
|
4075
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4076
|
+
};
|
3861
4077
|
}
|
3862
|
-
|
3863
|
-
|
3864
|
-
if (!draftVersion)
|
3865
|
-
return;
|
3866
|
-
return {
|
3867
|
-
...fp.pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
|
3868
|
-
status: this.getStatus(draftVersion, otherVersions)
|
3869
|
-
};
|
3870
|
-
}).filter(Boolean);
|
4078
|
+
);
|
4079
|
+
return mappingResult.filter(Boolean);
|
3871
4080
|
},
|
3872
4081
|
/**
|
3873
4082
|
* Returns available status of a document for the current locale
|
@@ -3905,26 +4114,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3905
4114
|
});
|
3906
4115
|
},
|
3907
4116
|
getStatus(version, otherDocumentStatuses) {
|
3908
|
-
|
3909
|
-
|
3910
|
-
|
4117
|
+
let draftVersion;
|
4118
|
+
let publishedVersion;
|
4119
|
+
if (version.publishedAt) {
|
4120
|
+
publishedVersion = version;
|
4121
|
+
} else {
|
4122
|
+
draftVersion = version;
|
3911
4123
|
}
|
3912
|
-
|
3913
|
-
|
3914
|
-
|
3915
|
-
|
3916
|
-
|
4124
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4125
|
+
if (otherVersion?.publishedAt) {
|
4126
|
+
publishedVersion = otherVersion;
|
4127
|
+
} else if (otherVersion) {
|
4128
|
+
draftVersion = otherVersion;
|
3917
4129
|
}
|
3918
|
-
if (
|
4130
|
+
if (!draftVersion)
|
3919
4131
|
return CONTENT_MANAGER_STATUS.PUBLISHED;
|
3920
|
-
|
3921
|
-
|
4132
|
+
if (!publishedVersion)
|
4133
|
+
return CONTENT_MANAGER_STATUS.DRAFT;
|
4134
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4135
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3922
4136
|
},
|
4137
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4138
|
+
// We could refactor this so the locales are only loaded when they're
|
4139
|
+
// needed. e.g. in the bulk locale action modal.
|
3923
4140
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4141
|
+
const populate = getValidatableFieldsPopulate(uid2);
|
3924
4142
|
const versions = await strapi2.db.query(uid2).findMany({
|
3925
4143
|
where: { documentId: version.documentId },
|
3926
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
3927
4144
|
populate: {
|
4145
|
+
// Populate only fields that require validation for bulk locale actions
|
4146
|
+
...populate,
|
4147
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3928
4148
|
createdBy: {
|
3929
4149
|
select: ["id", "firstname", "lastname", "email"]
|
3930
4150
|
},
|
@@ -3933,7 +4153,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3933
4153
|
}
|
3934
4154
|
}
|
3935
4155
|
});
|
3936
|
-
const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
|
4156
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
|
3937
4157
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3938
4158
|
return {
|
3939
4159
|
availableLocales: availableLocalesResult,
|
@@ -3946,8 +4166,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3946
4166
|
* - Available status of the document for the current locale
|
3947
4167
|
*/
|
3948
4168
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3949
|
-
if (!document)
|
3950
|
-
return
|
4169
|
+
if (!document) {
|
4170
|
+
return {
|
4171
|
+
data: document,
|
4172
|
+
meta: {
|
4173
|
+
availableLocales: [],
|
4174
|
+
availableStatus: []
|
4175
|
+
}
|
4176
|
+
};
|
4177
|
+
}
|
3951
4178
|
const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
|
3952
4179
|
if (!hasDraftAndPublish) {
|
3953
4180
|
opts.availableStatus = false;
|
@@ -3997,26 +4224,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
3997
4224
|
}, 0);
|
3998
4225
|
};
|
3999
4226
|
const { ApplicationError } = strapiUtils.errors;
|
4000
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
4001
4227
|
const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
|
4002
4228
|
const omitPublishedAtField = fp.omit(PUBLISHED_AT_ATTRIBUTE);
|
4003
4229
|
const omitIdField = fp.omit("id");
|
4004
|
-
const emitEvent = async (uid2, event, document) => {
|
4005
|
-
const modelDef = strapi.getModel(uid2);
|
4006
|
-
const sanitizedDocument = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
|
4007
|
-
{
|
4008
|
-
schema: modelDef,
|
4009
|
-
getModel(uid22) {
|
4010
|
-
return strapi.getModel(uid22);
|
4011
|
-
}
|
4012
|
-
},
|
4013
|
-
document
|
4014
|
-
);
|
4015
|
-
strapi.eventHub.emit(event, {
|
4016
|
-
model: modelDef.modelName,
|
4017
|
-
entry: sanitizedDocument
|
4018
|
-
});
|
4019
|
-
};
|
4020
4230
|
const documentManager = ({ strapi: strapi2 }) => {
|
4021
4231
|
return {
|
4022
4232
|
async findOne(id, uid2, opts = {}) {
|
@@ -4035,6 +4245,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4035
4245
|
} else if (opts.locale && opts.locale !== "*") {
|
4036
4246
|
where.locale = opts.locale;
|
4037
4247
|
}
|
4248
|
+
if (typeof opts.isPublished === "boolean") {
|
4249
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4250
|
+
}
|
4038
4251
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4039
4252
|
},
|
4040
4253
|
async findMany(opts, uid2) {
|
@@ -4042,20 +4255,16 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4042
4255
|
return strapi2.documents(uid2).findMany(params);
|
4043
4256
|
},
|
4044
4257
|
async findPage(opts, uid2) {
|
4045
|
-
const
|
4046
|
-
|
4258
|
+
const params = strapiUtils.pagination.withDefaultPagination(opts || {}, {
|
4259
|
+
maxLimit: 1e3
|
4260
|
+
});
|
4047
4261
|
const [documents, total = 0] = await Promise.all([
|
4048
|
-
strapi2.documents(uid2).findMany(
|
4049
|
-
strapi2.documents(uid2).count(
|
4262
|
+
strapi2.documents(uid2).findMany(params),
|
4263
|
+
strapi2.documents(uid2).count(params)
|
4050
4264
|
]);
|
4051
4265
|
return {
|
4052
4266
|
results: documents,
|
4053
|
-
pagination:
|
4054
|
-
page,
|
4055
|
-
pageSize,
|
4056
|
-
pageCount: Math.ceil(total / pageSize),
|
4057
|
-
total
|
4058
|
-
}
|
4267
|
+
pagination: strapiUtils.pagination.transformPagedPaginationInfo(params, total)
|
4059
4268
|
};
|
4060
4269
|
},
|
4061
4270
|
async create(uid2, opts = {}) {
|
@@ -4072,10 +4281,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4072
4281
|
async clone(id, body, uid2) {
|
4073
4282
|
const populate = await buildDeepPopulate(uid2);
|
4074
4283
|
const params = {
|
4075
|
-
data:
|
4076
|
-
...omitIdField(body),
|
4077
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4078
|
-
},
|
4284
|
+
data: omitIdField(body),
|
4079
4285
|
populate
|
4080
4286
|
};
|
4081
4287
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4101,70 +4307,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4101
4307
|
return {};
|
4102
4308
|
},
|
4103
4309
|
// FIXME: handle relations
|
4104
|
-
async deleteMany(
|
4105
|
-
const
|
4106
|
-
|
4107
|
-
|
4108
|
-
}
|
4109
|
-
return { count: docs.length };
|
4310
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4311
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4312
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4313
|
+
});
|
4314
|
+
return { count: deletedEntries.length };
|
4110
4315
|
},
|
4111
4316
|
async publish(id, uid2, opts = {}) {
|
4112
4317
|
const populate = await buildDeepPopulate(uid2);
|
4113
4318
|
const params = { ...opts, populate };
|
4114
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4319
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4115
4320
|
},
|
4116
|
-
async publishMany(
|
4117
|
-
|
4118
|
-
|
4119
|
-
|
4120
|
-
|
4121
|
-
|
4122
|
-
|
4123
|
-
strapi2.getModel(uid2),
|
4124
|
-
document,
|
4125
|
-
void 0,
|
4126
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4127
|
-
document
|
4128
|
-
);
|
4129
|
-
})
|
4130
|
-
);
|
4131
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4132
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4133
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4134
|
-
const populate = await buildDeepPopulate(uid2);
|
4135
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4136
|
-
where: filters,
|
4137
|
-
data
|
4138
|
-
});
|
4139
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4140
|
-
where: filters,
|
4141
|
-
populate
|
4321
|
+
async publishMany(uid2, documentIds, locale) {
|
4322
|
+
return strapi2.db.transaction(async () => {
|
4323
|
+
const results = await Promise.all(
|
4324
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4325
|
+
);
|
4326
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4327
|
+
return publishedEntitiesCount;
|
4142
4328
|
});
|
4143
|
-
await Promise.all(
|
4144
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4145
|
-
);
|
4146
|
-
return publishedEntitiesCount;
|
4147
4329
|
},
|
4148
|
-
async unpublishMany(
|
4149
|
-
|
4150
|
-
return
|
4151
|
-
|
4152
|
-
|
4153
|
-
|
4154
|
-
|
4155
|
-
const populate = await buildDeepPopulate(uid2);
|
4156
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4157
|
-
where: filters,
|
4158
|
-
data
|
4159
|
-
});
|
4160
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4161
|
-
where: filters,
|
4162
|
-
populate
|
4330
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4331
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4332
|
+
return Promise.all(
|
4333
|
+
documentIds.map(
|
4334
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4335
|
+
)
|
4336
|
+
);
|
4163
4337
|
});
|
4164
|
-
|
4165
|
-
|
4166
|
-
);
|
4167
|
-
return unpublishedEntitiesCount;
|
4338
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4339
|
+
return { count: unpublishedEntitiesCount };
|
4168
4340
|
},
|
4169
4341
|
async unpublish(id, uid2, opts = {}) {
|
4170
4342
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4189,16 +4361,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4189
4361
|
}
|
4190
4362
|
return sumDraftCounts(document, uid2);
|
4191
4363
|
},
|
4192
|
-
async countManyEntriesDraftRelations(
|
4364
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4193
4365
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4194
4366
|
if (!hasRelations) {
|
4195
4367
|
return 0;
|
4196
4368
|
}
|
4369
|
+
let localeFilter = {};
|
4370
|
+
if (locale) {
|
4371
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4372
|
+
}
|
4197
4373
|
const entities = await strapi2.db.query(uid2).findMany({
|
4198
4374
|
populate,
|
4199
4375
|
where: {
|
4200
|
-
|
4201
|
-
...
|
4376
|
+
documentId: { $in: documentIds },
|
4377
|
+
...localeFilter
|
4202
4378
|
}
|
4203
4379
|
});
|
4204
4380
|
const totalNumberDraftRelations = entities.reduce(
|