@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.1fc4b627b49f713b07ed9f7f2b37741dcf8cf736
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
- package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
- package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs → ComponentConfigurationPage-CIjXcRAB.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-CIjXcRAB.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-gsCd80MU.js} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-gsCd80MU.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-BoBb-DLH.mjs → EditConfigurationPage-BglmD_BF.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-BglmD_BF.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-DHDQKBzw.js} +4 -4
- package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-DHDQKBzw.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-KRG56aCq.js → EditViewPage-C4iTxUPU.js} +69 -50
- package/dist/_chunks/EditViewPage-C4iTxUPU.js.map +1 -0
- package/dist/_chunks/{EditViewPage-aUnqL-63.mjs → EditViewPage-CiwVPMaK.mjs} +70 -49
- package/dist/_chunks/EditViewPage-CiwVPMaK.mjs.map +1 -0
- package/dist/_chunks/{Field-kVFO4ZKB.mjs → Field-DIjL1b5d.mjs} +1046 -802
- package/dist/_chunks/Field-DIjL1b5d.mjs.map +1 -0
- package/dist/_chunks/{Field-kq1c2TF1.js → Field-DhXEK8y1.js} +1092 -849
- package/dist/_chunks/Field-DhXEK8y1.js.map +1 -0
- package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-CmNesrvR.mjs} +66 -45
- package/dist/_chunks/Form-CmNesrvR.mjs.map +1 -0
- package/dist/_chunks/{Form-CQ67ZifP.js → Form-CwmJ4sWe.js} +66 -46
- package/dist/_chunks/Form-CwmJ4sWe.js.map +1 -0
- package/dist/_chunks/{History-BLEnudTX.js → History-BLCCNgCt.js} +164 -54
- package/dist/_chunks/History-BLCCNgCt.js.map +1 -0
- package/dist/_chunks/{History-DKhZAPcK.mjs → History-D-99Wh30.mjs} +163 -52
- package/dist/_chunks/History-D-99Wh30.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-DxWpeZrO.js} +68 -59
- package/dist/_chunks/ListConfigurationPage-DxWpeZrO.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-JPWZz7Kg.mjs} +64 -54
- package/dist/_chunks/ListConfigurationPage-JPWZz7Kg.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-CIQekSFz.js} +143 -139
- package/dist/_chunks/ListViewPage-CIQekSFz.js.map +1 -0
- package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-DSK3f0ST.mjs} +140 -136
- package/dist/_chunks/ListViewPage-DSK3f0ST.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-C5cxKvC2.js} +3 -3
- package/dist/_chunks/NoContentTypePage-C5cxKvC2.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-D99LU1YP.mjs} +3 -3
- package/dist/_chunks/NoContentTypePage-D99LU1YP.mjs.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-DBrBw-0y.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-DBrBw-0y.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-Oy4tmUrW.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-Oy4tmUrW.js.map} +1 -1
- package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-BBmhcWFV.mjs} +132 -89
- package/dist/_chunks/Relations-BBmhcWFV.mjs.map +1 -0
- package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-eG-9p_qS.js} +135 -93
- package/dist/_chunks/Relations-eG-9p_qS.js.map +1 -0
- package/dist/_chunks/{en-C-V1_90f.js → en-Bm0D0IWz.js} +23 -15
- package/dist/_chunks/{en-C-V1_90f.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-MBPul9Su.mjs → en-DKV44jRb.mjs} +23 -15
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-DNa1J4HE.js → index-BIWDoFLK.js} +1877 -939
- package/dist/_chunks/index-BIWDoFLK.js.map +1 -0
- package/dist/_chunks/{index-CAc9yTnx.mjs → index-BrUzbQ30.mjs} +1902 -964
- package/dist/_chunks/index-BrUzbQ30.mjs.map +1 -0
- package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-_5-cXs34.mjs} +45 -27
- package/dist/_chunks/layout-_5-cXs34.mjs.map +1 -0
- package/dist/_chunks/{layout-BqtLA6Lb.js → layout-lMc9i1-Z.js} +45 -29
- package/dist/_chunks/layout-lMc9i1-Z.js.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-BHY_KDJ_.js → relations-BRHithi8.js} +3 -7
- package/dist/_chunks/relations-BRHithi8.js.map +1 -0
- package/dist/_chunks/{relations-mMFEcZRq.mjs → relations-B_VLk-DD.mjs} +3 -7
- package/dist/_chunks/relations-B_VLk-DD.mjs.map +1 -0
- package/dist/_chunks/useDebounce-CtcjDB3L.js +28 -0
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
- package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +9 -7
- 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 +2 -1
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +37 -9
- package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
- package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
- package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/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 +16 -53
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
- package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
- package/dist/admin/src/preview/constants.d.ts +1 -0
- package/dist/admin/src/preview/index.d.ts +4 -0
- package/dist/admin/src/services/api.d.ts +2 -3
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +5 -5
- package/dist/admin/src/services/documents.d.ts +31 -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 +5 -7
- package/dist/server/index.js +571 -312
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +573 -314
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/single-types.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +22 -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.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +20 -36
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/preview/constants.d.ts +2 -0
- package/dist/server/src/preview/constants.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/index.d.ts +2 -0
- package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/preview.d.ts +9 -0
- package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
- package/dist/server/src/preview/index.d.ts +4 -0
- package/dist/server/src/preview/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/index.d.ts +8 -0
- package/dist/server/src/preview/routes/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/preview.d.ts +4 -0
- package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
- package/dist/server/src/preview/services/index.d.ts +4 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview.d.ts +6 -0
- package/dist/server/src/preview/services/preview.d.ts.map +1 -0
- package/dist/server/src/preview/utils.d.ts +7 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts +11 -6
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +14 -35
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +20 -36
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/services/utils/populate.d.ts +8 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +17 -7
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/relations.d.ts +2 -2
- package/dist/shared/contracts/relations.d.ts.map +1 -1
- package/package.json +17 -18
- package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
- package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
- package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
- package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
- package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
- package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
- package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
- package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
- package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
- package/dist/_chunks/History-BLEnudTX.js.map +0 -1
- package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
- package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
- package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
- package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
- package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
- package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
- package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
- package/dist/_chunks/relations-BHY_KDJ_.js.map +0 -1
- package/dist/_chunks/relations-mMFEcZRq.mjs.map +0 -1
- package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
- package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
- package/dist/_chunks/urls-DzZya_gm.js +0 -6
- package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
- package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
- package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.js
CHANGED
@@ -121,7 +121,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
121
121
|
}
|
122
122
|
};
|
123
123
|
};
|
124
|
-
const controllers$
|
124
|
+
const controllers$2 = {
|
125
125
|
"history-version": createHistoryVersionController
|
126
126
|
/**
|
127
127
|
* Casting is needed because the types aren't aware that Strapi supports
|
@@ -199,7 +199,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
199
199
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
200
200
|
};
|
201
201
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
202
|
+
const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
|
202
203
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
204
|
+
const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
|
203
205
|
const getLocaleDictionary = async () => {
|
204
206
|
if (!localesService)
|
205
207
|
return {};
|
@@ -226,20 +228,25 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
226
228
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
227
229
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
228
230
|
};
|
229
|
-
const getDeepPopulate2 = (uid2) => {
|
231
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
230
232
|
const model = strapi2.getModel(uid2);
|
231
233
|
const attributes = Object.entries(model.attributes);
|
234
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
232
235
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
233
236
|
switch (attribute.type) {
|
234
237
|
case "relation": {
|
238
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
239
|
+
if (isMorphRelation) {
|
240
|
+
break;
|
241
|
+
}
|
235
242
|
const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
|
236
243
|
if (isVisible2) {
|
237
|
-
acc[attributeName] = {
|
244
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
238
245
|
}
|
239
246
|
break;
|
240
247
|
}
|
241
248
|
case "media": {
|
242
|
-
acc[attributeName] = {
|
249
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
243
250
|
break;
|
244
251
|
}
|
245
252
|
case "component": {
|
@@ -312,6 +319,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
312
319
|
getRelationRestoreValue,
|
313
320
|
getMediaRestoreValue,
|
314
321
|
getDefaultLocale,
|
322
|
+
isLocalizedContentType,
|
315
323
|
getLocaleDictionary,
|
316
324
|
getRetentionDays,
|
317
325
|
getVersionStatus,
|
@@ -334,7 +342,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
334
342
|
});
|
335
343
|
},
|
336
344
|
async findVersionsPage(params) {
|
337
|
-
const
|
345
|
+
const model = strapi2.getModel(params.query.contentType);
|
346
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
347
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
348
|
+
let locale = null;
|
349
|
+
if (isLocalizedContentType) {
|
350
|
+
locale = params.query.locale || defaultLocale;
|
351
|
+
}
|
338
352
|
const [{ results, pagination }, localeDictionary] = await Promise.all([
|
339
353
|
query.findPage({
|
340
354
|
...params.query,
|
@@ -379,7 +393,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
379
393
|
if (userToPopulate == null) {
|
380
394
|
return null;
|
381
395
|
}
|
382
|
-
return strapi2.query("admin::user").findOne({
|
396
|
+
return strapi2.query("admin::user").findOne({
|
397
|
+
where: {
|
398
|
+
...userToPopulate.id ? { id: userToPopulate.id } : {},
|
399
|
+
...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
|
400
|
+
}
|
401
|
+
});
|
383
402
|
})
|
384
403
|
);
|
385
404
|
return {
|
@@ -490,13 +509,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
490
509
|
}
|
491
510
|
};
|
492
511
|
};
|
512
|
+
const shouldCreateHistoryVersion = (context) => {
|
513
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
514
|
+
return false;
|
515
|
+
}
|
516
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
517
|
+
return false;
|
518
|
+
}
|
519
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
520
|
+
return false;
|
521
|
+
}
|
522
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
523
|
+
return false;
|
524
|
+
}
|
525
|
+
return true;
|
526
|
+
};
|
527
|
+
const getSchemas = (uid2) => {
|
528
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
529
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
530
|
+
(currentComponentSchemas, key) => {
|
531
|
+
const fieldSchema = attributesSchema[key];
|
532
|
+
if (fieldSchema.type === "component") {
|
533
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
534
|
+
return {
|
535
|
+
...currentComponentSchemas,
|
536
|
+
[fieldSchema.component]: componentSchema
|
537
|
+
};
|
538
|
+
}
|
539
|
+
return currentComponentSchemas;
|
540
|
+
},
|
541
|
+
{}
|
542
|
+
);
|
543
|
+
return {
|
544
|
+
schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
|
545
|
+
componentsSchemas
|
546
|
+
};
|
547
|
+
};
|
493
548
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
494
549
|
const state = {
|
495
550
|
deleteExpiredJob: null,
|
496
551
|
isInitialized: false
|
497
552
|
};
|
498
|
-
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
499
|
-
const historyService = getService(strapi2, "history");
|
500
553
|
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
501
554
|
return {
|
502
555
|
async bootstrap() {
|
@@ -504,60 +557,53 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
504
557
|
return;
|
505
558
|
}
|
506
559
|
strapi2.documents.use(async (context, next) => {
|
507
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
508
|
-
return next();
|
509
|
-
}
|
510
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
511
|
-
return next();
|
512
|
-
}
|
513
|
-
const contentTypeUid = context.contentType.uid;
|
514
|
-
if (!contentTypeUid.startsWith("api::")) {
|
515
|
-
return next();
|
516
|
-
}
|
517
560
|
const result = await next();
|
518
|
-
|
561
|
+
if (!shouldCreateHistoryVersion(context)) {
|
562
|
+
return result;
|
563
|
+
}
|
564
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
519
565
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
520
|
-
const
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
566
|
+
const locales = fp.castArray(context.params?.locale || defaultLocale);
|
567
|
+
if (!locales.length) {
|
568
|
+
return result;
|
569
|
+
}
|
570
|
+
const uid2 = context.contentType.uid;
|
571
|
+
const schemas = getSchemas(uid2);
|
572
|
+
const model = strapi2.getModel(uid2);
|
573
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
574
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
575
|
+
where: {
|
576
|
+
documentId,
|
577
|
+
...isLocalizedContentType ? { locale: { $in: locales } } : {},
|
578
|
+
...strapiUtils.contentTypes.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
|
579
|
+
},
|
580
|
+
populate: serviceUtils.getDeepPopulate(
|
581
|
+
uid2,
|
582
|
+
true
|
583
|
+
/* use database syntax */
|
584
|
+
)
|
525
585
|
});
|
526
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
527
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
528
|
-
const componentsSchemas = Object.keys(
|
529
|
-
attributesSchema
|
530
|
-
).reduce((currentComponentSchemas, key) => {
|
531
|
-
const fieldSchema = attributesSchema[key];
|
532
|
-
if (fieldSchema.type === "component") {
|
533
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
534
|
-
return {
|
535
|
-
...currentComponentSchemas,
|
536
|
-
[fieldSchema.component]: componentSchema
|
537
|
-
};
|
538
|
-
}
|
539
|
-
return currentComponentSchemas;
|
540
|
-
}, {});
|
541
586
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
542
|
-
onCommit(() => {
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
587
|
+
onCommit(async () => {
|
588
|
+
for (const entry of localeEntries) {
|
589
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
590
|
+
await getService(strapi2, "history").createVersion({
|
591
|
+
contentType: uid2,
|
592
|
+
data: fp.omit(FIELDS_TO_IGNORE, entry),
|
593
|
+
relatedDocumentId: documentId,
|
594
|
+
locale: entry.locale,
|
595
|
+
status,
|
596
|
+
...schemas
|
597
|
+
});
|
598
|
+
}
|
552
599
|
});
|
553
600
|
});
|
554
601
|
return result;
|
555
602
|
});
|
556
|
-
const retentionDays = serviceUtils.getRetentionDays();
|
557
603
|
state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
|
558
|
-
const retentionDaysInMilliseconds =
|
604
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
559
605
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
560
|
-
query.deleteMany({
|
606
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
561
607
|
where: {
|
562
608
|
created_at: {
|
563
609
|
$lt: expirationDate.toISOString()
|
@@ -574,17 +620,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
574
620
|
}
|
575
621
|
};
|
576
622
|
};
|
577
|
-
const services$
|
623
|
+
const services$2 = {
|
578
624
|
history: createHistoryService,
|
579
625
|
lifecycles: createLifecyclesService
|
580
626
|
};
|
581
|
-
const info = { pluginName: "content-manager", type: "admin" };
|
627
|
+
const info$1 = { pluginName: "content-manager", type: "admin" };
|
582
628
|
const historyVersionRouter = {
|
583
629
|
type: "admin",
|
584
630
|
routes: [
|
585
631
|
{
|
586
632
|
method: "GET",
|
587
|
-
info,
|
633
|
+
info: info$1,
|
588
634
|
path: "/history-versions",
|
589
635
|
handler: "history-version.findMany",
|
590
636
|
config: {
|
@@ -593,7 +639,7 @@ const historyVersionRouter = {
|
|
593
639
|
},
|
594
640
|
{
|
595
641
|
method: "PUT",
|
596
|
-
info,
|
642
|
+
info: info$1,
|
597
643
|
path: "/history-versions/:versionId/restore",
|
598
644
|
handler: "history-version.restoreVersion",
|
599
645
|
config: {
|
@@ -602,7 +648,7 @@ const historyVersionRouter = {
|
|
602
648
|
}
|
603
649
|
]
|
604
650
|
};
|
605
|
-
const routes$
|
651
|
+
const routes$2 = {
|
606
652
|
"history-version": historyVersionRouter
|
607
653
|
};
|
608
654
|
const historyVersion = {
|
@@ -649,7 +695,7 @@ const historyVersion = {
|
|
649
695
|
}
|
650
696
|
}
|
651
697
|
};
|
652
|
-
const getFeature = () => {
|
698
|
+
const getFeature$1 = () => {
|
653
699
|
if (strapi.ee.features.isEnabled("cms-content-history")) {
|
654
700
|
return {
|
655
701
|
register({ strapi: strapi2 }) {
|
@@ -661,9 +707,9 @@ const getFeature = () => {
|
|
661
707
|
destroy({ strapi: strapi2 }) {
|
662
708
|
getService(strapi2, "lifecycles").destroy();
|
663
709
|
},
|
664
|
-
controllers: controllers$
|
665
|
-
services: services$
|
666
|
-
routes: routes$
|
710
|
+
controllers: controllers$2,
|
711
|
+
services: services$2,
|
712
|
+
routes: routes$2
|
667
713
|
};
|
668
714
|
}
|
669
715
|
return {
|
@@ -672,7 +718,7 @@ const getFeature = () => {
|
|
672
718
|
}
|
673
719
|
};
|
674
720
|
};
|
675
|
-
const history = getFeature();
|
721
|
+
const history = getFeature$1();
|
676
722
|
const register = async ({ strapi: strapi2 }) => {
|
677
723
|
await history.register?.({ strapi: strapi2 });
|
678
724
|
};
|
@@ -680,6 +726,62 @@ const ALLOWED_WEBHOOK_EVENTS = {
|
|
680
726
|
ENTRY_PUBLISH: "entry.publish",
|
681
727
|
ENTRY_UNPUBLISH: "entry.unpublish"
|
682
728
|
};
|
729
|
+
const FEATURE_ID = "preview";
|
730
|
+
const info = { pluginName: "content-manager", type: "admin" };
|
731
|
+
const previewRouter = {
|
732
|
+
type: "admin",
|
733
|
+
routes: [
|
734
|
+
{
|
735
|
+
method: "GET",
|
736
|
+
info,
|
737
|
+
path: "/preview/url/:contentType",
|
738
|
+
handler: "preview.getPreviewURL",
|
739
|
+
config: {
|
740
|
+
policies: ["admin::isAuthenticatedAdmin"]
|
741
|
+
}
|
742
|
+
}
|
743
|
+
]
|
744
|
+
};
|
745
|
+
const routes$1 = {
|
746
|
+
preview: previewRouter
|
747
|
+
};
|
748
|
+
const createPreviewController = () => {
|
749
|
+
return {
|
750
|
+
async getPreviewURL(ctx) {
|
751
|
+
ctx.request;
|
752
|
+
return {
|
753
|
+
data: { url: "" }
|
754
|
+
};
|
755
|
+
}
|
756
|
+
};
|
757
|
+
};
|
758
|
+
const controllers$1 = {
|
759
|
+
preview: createPreviewController
|
760
|
+
/**
|
761
|
+
* Casting is needed because the types aren't aware that Strapi supports
|
762
|
+
* passing a controller factory as the value, instead of a controller object directly
|
763
|
+
*/
|
764
|
+
};
|
765
|
+
const createPreviewService = () => {
|
766
|
+
};
|
767
|
+
const services$1 = {
|
768
|
+
preview: createPreviewService
|
769
|
+
};
|
770
|
+
const getFeature = () => {
|
771
|
+
if (!strapi.features.future.isEnabled(FEATURE_ID)) {
|
772
|
+
return {};
|
773
|
+
}
|
774
|
+
return {
|
775
|
+
bootstrap() {
|
776
|
+
console.log("Bootstrapping preview server");
|
777
|
+
strapi.config.get("admin.preview");
|
778
|
+
},
|
779
|
+
routes: routes$1,
|
780
|
+
controllers: controllers$1,
|
781
|
+
services: services$1
|
782
|
+
};
|
783
|
+
};
|
784
|
+
const preview = getFeature();
|
683
785
|
const bootstrap = async () => {
|
684
786
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
685
787
|
strapi.get("webhookStore").addAllowedEvent(key, value);
|
@@ -689,6 +791,7 @@ const bootstrap = async () => {
|
|
689
791
|
await getService$1("content-types").syncConfigurations();
|
690
792
|
await getService$1("permission").registerPermissions();
|
691
793
|
await history.bootstrap?.({ strapi });
|
794
|
+
await preview.bootstrap?.({ strapi });
|
692
795
|
};
|
693
796
|
const destroy = async ({ strapi: strapi2 }) => {
|
694
797
|
await history.destroy?.({ strapi: strapi2 });
|
@@ -1178,7 +1281,8 @@ const admin = {
|
|
1178
1281
|
};
|
1179
1282
|
const routes = {
|
1180
1283
|
admin,
|
1181
|
-
...history.routes ? history.routes : {}
|
1284
|
+
...history.routes ? history.routes : {},
|
1285
|
+
...preview.routes ? preview.routes : {}
|
1182
1286
|
};
|
1183
1287
|
const hasPermissionsSchema = strapiUtils.yup.object({
|
1184
1288
|
actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
|
@@ -1189,6 +1293,11 @@ const { createPolicy } = strapiUtils.policy;
|
|
1189
1293
|
const hasPermissions = createPolicy({
|
1190
1294
|
name: "plugin::content-manager.hasPermissions",
|
1191
1295
|
validator: validateHasPermissionsInput,
|
1296
|
+
/**
|
1297
|
+
* NOTE: Action aliases are currently not checked at this level (policy).
|
1298
|
+
* This is currently the intended behavior to avoid changing the behavior of API related permissions.
|
1299
|
+
* If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
|
1300
|
+
*/
|
1192
1301
|
handler(ctx, config = {}) {
|
1193
1302
|
const { actions = [], hasAtLeastOne = false } = config;
|
1194
1303
|
const { userAbility } = ctx.state;
|
@@ -1478,7 +1587,7 @@ const { PaginationError, ValidationError } = strapiUtils.errors;
|
|
1478
1587
|
const TYPES = ["singleType", "collectionType"];
|
1479
1588
|
const kindSchema = strapiUtils.yup.string().oneOf(TYPES).nullable();
|
1480
1589
|
const bulkActionInputSchema = strapiUtils.yup.object({
|
1481
|
-
|
1590
|
+
documentIds: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
|
1482
1591
|
}).required();
|
1483
1592
|
const generateUIDInputSchema = strapiUtils.yup.object({
|
1484
1593
|
contentTypeUID: strapiUtils.yup.string().required(),
|
@@ -1577,15 +1686,49 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1577
1686
|
}
|
1578
1687
|
}, body);
|
1579
1688
|
};
|
1580
|
-
const
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1689
|
+
const singleLocaleSchema = strapiUtils.yup.string().nullable();
|
1690
|
+
const multipleLocaleSchema = strapiUtils.yup.lazy(
|
1691
|
+
(value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1692
|
+
);
|
1693
|
+
const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
|
1694
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1695
|
+
const { allowMultipleLocales } = opts;
|
1696
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1697
|
+
const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1698
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1699
|
+
const schema = strapiUtils.yup.object().shape({
|
1700
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1701
|
+
status: statusSchema
|
1702
|
+
});
|
1703
|
+
try {
|
1704
|
+
await strapiUtils.validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1705
|
+
return { locale, status, ...rest };
|
1706
|
+
} catch (error) {
|
1707
|
+
throw new strapiUtils.errors.ValidationError(`Validation error: ${error.message}`);
|
1587
1708
|
}
|
1588
|
-
|
1709
|
+
};
|
1710
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1711
|
+
const documentMetadata2 = getService$1("document-metadata");
|
1712
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1713
|
+
let {
|
1714
|
+
meta: { availableLocales, availableStatus }
|
1715
|
+
} = serviceOutput;
|
1716
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1717
|
+
availableLocales = await strapiUtils.async.map(
|
1718
|
+
availableLocales,
|
1719
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1720
|
+
);
|
1721
|
+
availableStatus = await strapiUtils.async.map(
|
1722
|
+
availableStatus,
|
1723
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1724
|
+
);
|
1725
|
+
return {
|
1726
|
+
...serviceOutput,
|
1727
|
+
meta: {
|
1728
|
+
availableLocales,
|
1729
|
+
availableStatus
|
1730
|
+
}
|
1731
|
+
};
|
1589
1732
|
};
|
1590
1733
|
const createDocument = async (ctx, opts) => {
|
1591
1734
|
const { userAbility, user } = ctx.state;
|
@@ -1600,7 +1743,7 @@ const createDocument = async (ctx, opts) => {
|
|
1600
1743
|
const setCreator = strapiUtils.setCreatorFields({ user });
|
1601
1744
|
const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
|
1602
1745
|
const sanitizedBody = await sanitizeFn(body);
|
1603
|
-
const { locale, status
|
1746
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1604
1747
|
return documentManager2.create(model, {
|
1605
1748
|
data: sanitizedBody,
|
1606
1749
|
locale,
|
@@ -1619,7 +1762,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1619
1762
|
}
|
1620
1763
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1621
1764
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1622
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1765
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1623
1766
|
const [documentVersion, documentExists] = await Promise.all([
|
1624
1767
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1625
1768
|
documentManager2.exists(model, id)
|
@@ -1635,7 +1778,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1635
1778
|
throw new strapiUtils.errors.ForbiddenError();
|
1636
1779
|
}
|
1637
1780
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1638
|
-
const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
|
1781
|
+
const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
|
1639
1782
|
const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
|
1640
1783
|
const sanitizedBody = await sanitizeFn(body);
|
1641
1784
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1657,7 +1800,7 @@ const collectionTypes = {
|
|
1657
1800
|
}
|
1658
1801
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1659
1802
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1660
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
1803
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1661
1804
|
const { results: documents, pagination } = await documentManager2.findPage(
|
1662
1805
|
{ ...permissionQuery, populate, locale, status },
|
1663
1806
|
model
|
@@ -1686,14 +1829,13 @@ const collectionTypes = {
|
|
1686
1829
|
const { userAbility } = ctx.state;
|
1687
1830
|
const { model, id } = ctx.params;
|
1688
1831
|
const documentManager2 = getService$1("document-manager");
|
1689
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1690
1832
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1691
1833
|
if (permissionChecker2.cannot.read()) {
|
1692
1834
|
return ctx.forbidden();
|
1693
1835
|
}
|
1694
1836
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1695
1837
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1696
|
-
const { locale, status
|
1838
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1697
1839
|
const version = await documentManager2.findOne(id, model, {
|
1698
1840
|
populate,
|
1699
1841
|
locale,
|
@@ -1704,9 +1846,11 @@ const collectionTypes = {
|
|
1704
1846
|
if (!exists) {
|
1705
1847
|
return ctx.notFound();
|
1706
1848
|
}
|
1707
|
-
const { meta } = await
|
1849
|
+
const { meta } = await formatDocumentWithMetadata(
|
1850
|
+
permissionChecker2,
|
1708
1851
|
model,
|
1709
|
-
|
1852
|
+
// @ts-expect-error TODO: fix
|
1853
|
+
{ documentId: id, locale, publishedAt: null },
|
1710
1854
|
{ availableLocales: true, availableStatus: false }
|
1711
1855
|
);
|
1712
1856
|
ctx.body = { data: {}, meta };
|
@@ -1716,12 +1860,11 @@ const collectionTypes = {
|
|
1716
1860
|
return ctx.forbidden();
|
1717
1861
|
}
|
1718
1862
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1719
|
-
ctx.body = await
|
1863
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1720
1864
|
},
|
1721
1865
|
async create(ctx) {
|
1722
1866
|
const { userAbility } = ctx.state;
|
1723
1867
|
const { model } = ctx.params;
|
1724
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1725
1868
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1726
1869
|
const [totalEntries, document] = await Promise.all([
|
1727
1870
|
strapi.db.query(model).count(),
|
@@ -1729,7 +1872,7 @@ const collectionTypes = {
|
|
1729
1872
|
]);
|
1730
1873
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1731
1874
|
ctx.status = 201;
|
1732
|
-
ctx.body = await
|
1875
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1733
1876
|
// Empty metadata as it's not relevant for a new document
|
1734
1877
|
availableLocales: false,
|
1735
1878
|
availableStatus: false
|
@@ -1743,25 +1886,23 @@ const collectionTypes = {
|
|
1743
1886
|
async update(ctx) {
|
1744
1887
|
const { userAbility } = ctx.state;
|
1745
1888
|
const { model } = ctx.params;
|
1746
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1747
1889
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1748
1890
|
const updatedVersion = await updateDocument(ctx);
|
1749
1891
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1750
|
-
ctx.body = await
|
1892
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1751
1893
|
},
|
1752
1894
|
async clone(ctx) {
|
1753
1895
|
const { userAbility, user } = ctx.state;
|
1754
1896
|
const { model, sourceId: id } = ctx.params;
|
1755
1897
|
const { body } = ctx.request;
|
1756
1898
|
const documentManager2 = getService$1("document-manager");
|
1757
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1758
1899
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1759
1900
|
if (permissionChecker2.cannot.create()) {
|
1760
1901
|
return ctx.forbidden();
|
1761
1902
|
}
|
1762
1903
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1763
1904
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1764
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1905
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1765
1906
|
const document = await documentManager2.findOne(id, model, {
|
1766
1907
|
populate,
|
1767
1908
|
locale,
|
@@ -1777,7 +1918,7 @@ const collectionTypes = {
|
|
1777
1918
|
const sanitizedBody = await sanitizeFn(body);
|
1778
1919
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1779
1920
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1780
|
-
ctx.body = await
|
1921
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1781
1922
|
// Empty metadata as it's not relevant for a new document
|
1782
1923
|
availableLocales: false,
|
1783
1924
|
availableStatus: false
|
@@ -1806,7 +1947,7 @@ const collectionTypes = {
|
|
1806
1947
|
}
|
1807
1948
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1808
1949
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1809
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
1950
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1810
1951
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1811
1952
|
if (documentLocales.length === 0) {
|
1812
1953
|
return ctx.notFound();
|
@@ -1828,7 +1969,6 @@ const collectionTypes = {
|
|
1828
1969
|
const { id, model } = ctx.params;
|
1829
1970
|
const { body } = ctx.request;
|
1830
1971
|
const documentManager2 = getService$1("document-manager");
|
1831
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1832
1972
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1833
1973
|
if (permissionChecker2.cannot.publish()) {
|
1834
1974
|
return ctx.forbidden();
|
@@ -1836,25 +1976,52 @@ const collectionTypes = {
|
|
1836
1976
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1837
1977
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1838
1978
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1839
|
-
|
1979
|
+
let document;
|
1980
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1981
|
+
const isCreate = fp.isNil(id);
|
1982
|
+
if (isCreate) {
|
1983
|
+
if (permissionChecker2.cannot.create()) {
|
1984
|
+
throw new strapiUtils.errors.ForbiddenError();
|
1985
|
+
}
|
1986
|
+
document = await createDocument(ctx, { populate });
|
1987
|
+
}
|
1988
|
+
const isUpdate = !isCreate;
|
1989
|
+
if (isUpdate) {
|
1990
|
+
const documentExists = documentManager2.exists(model, id);
|
1991
|
+
if (!documentExists) {
|
1992
|
+
throw new strapiUtils.errors.NotFoundError("Document not found");
|
1993
|
+
}
|
1994
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
1995
|
+
if (!document) {
|
1996
|
+
if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
|
1997
|
+
throw new strapiUtils.errors.ForbiddenError();
|
1998
|
+
}
|
1999
|
+
document = await updateDocument(ctx);
|
2000
|
+
} else if (permissionChecker2.can.update(document)) {
|
2001
|
+
await updateDocument(ctx);
|
2002
|
+
}
|
2003
|
+
}
|
1840
2004
|
if (permissionChecker2.cannot.publish(document)) {
|
1841
2005
|
throw new strapiUtils.errors.ForbiddenError();
|
1842
2006
|
}
|
1843
|
-
const
|
1844
|
-
return documentManager2.publish(document.documentId, model, {
|
2007
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1845
2008
|
locale
|
1846
2009
|
// TODO: Allow setting creator fields on publish
|
1847
2010
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1848
2011
|
});
|
2012
|
+
if (!publishResult || publishResult.length === 0) {
|
2013
|
+
throw new strapiUtils.errors.NotFoundError("Document not found or already published.");
|
2014
|
+
}
|
2015
|
+
return publishResult[0];
|
1849
2016
|
});
|
1850
2017
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1851
|
-
ctx.body = await
|
2018
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1852
2019
|
},
|
1853
2020
|
async bulkPublish(ctx) {
|
1854
2021
|
const { userAbility } = ctx.state;
|
1855
2022
|
const { model } = ctx.params;
|
1856
2023
|
const { body } = ctx.request;
|
1857
|
-
const {
|
2024
|
+
const { documentIds } = body;
|
1858
2025
|
await validateBulkActionInput(body);
|
1859
2026
|
const documentManager2 = getService$1("document-manager");
|
1860
2027
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1863,8 +2030,13 @@ const collectionTypes = {
|
|
1863
2030
|
}
|
1864
2031
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1865
2032
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1866
|
-
const
|
1867
|
-
|
2033
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2034
|
+
allowMultipleLocales: true
|
2035
|
+
});
|
2036
|
+
const entityPromises = documentIds.map(
|
2037
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
2038
|
+
);
|
2039
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1868
2040
|
for (const entity of entities) {
|
1869
2041
|
if (!entity) {
|
1870
2042
|
return ctx.notFound();
|
@@ -1873,24 +2045,27 @@ const collectionTypes = {
|
|
1873
2045
|
return ctx.forbidden();
|
1874
2046
|
}
|
1875
2047
|
}
|
1876
|
-
const
|
2048
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1877
2049
|
ctx.body = { count };
|
1878
2050
|
},
|
1879
2051
|
async bulkUnpublish(ctx) {
|
1880
2052
|
const { userAbility } = ctx.state;
|
1881
2053
|
const { model } = ctx.params;
|
1882
2054
|
const { body } = ctx.request;
|
1883
|
-
const {
|
2055
|
+
const { documentIds } = body;
|
1884
2056
|
await validateBulkActionInput(body);
|
1885
2057
|
const documentManager2 = getService$1("document-manager");
|
1886
2058
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1887
2059
|
if (permissionChecker2.cannot.unpublish()) {
|
1888
2060
|
return ctx.forbidden();
|
1889
2061
|
}
|
1890
|
-
const
|
1891
|
-
|
1892
|
-
|
1893
|
-
const
|
2062
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2063
|
+
allowMultipleLocales: true
|
2064
|
+
});
|
2065
|
+
const entityPromises = documentIds.map(
|
2066
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
2067
|
+
);
|
2068
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1894
2069
|
for (const entity of entities) {
|
1895
2070
|
if (!entity) {
|
1896
2071
|
return ctx.notFound();
|
@@ -1899,7 +2074,8 @@ const collectionTypes = {
|
|
1899
2074
|
return ctx.forbidden();
|
1900
2075
|
}
|
1901
2076
|
}
|
1902
|
-
const
|
2077
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
2078
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1903
2079
|
ctx.body = { count };
|
1904
2080
|
},
|
1905
2081
|
async unpublish(ctx) {
|
@@ -1909,7 +2085,6 @@ const collectionTypes = {
|
|
1909
2085
|
body: { discardDraft, ...body }
|
1910
2086
|
} = ctx.request;
|
1911
2087
|
const documentManager2 = getService$1("document-manager");
|
1912
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1913
2088
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1914
2089
|
if (permissionChecker2.cannot.unpublish()) {
|
1915
2090
|
return ctx.forbidden();
|
@@ -1919,7 +2094,7 @@ const collectionTypes = {
|
|
1919
2094
|
}
|
1920
2095
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1921
2096
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1922
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2097
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1923
2098
|
const document = await documentManager2.findOne(id, model, {
|
1924
2099
|
populate,
|
1925
2100
|
locale,
|
@@ -1941,7 +2116,7 @@ const collectionTypes = {
|
|
1941
2116
|
ctx.body = await strapiUtils.async.pipe(
|
1942
2117
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1943
2118
|
permissionChecker2.sanitizeOutput,
|
1944
|
-
(document2) =>
|
2119
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1945
2120
|
)(document);
|
1946
2121
|
});
|
1947
2122
|
},
|
@@ -1950,14 +2125,13 @@ const collectionTypes = {
|
|
1950
2125
|
const { id, model } = ctx.params;
|
1951
2126
|
const { body } = ctx.request;
|
1952
2127
|
const documentManager2 = getService$1("document-manager");
|
1953
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1954
2128
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1955
2129
|
if (permissionChecker2.cannot.discard()) {
|
1956
2130
|
return ctx.forbidden();
|
1957
2131
|
}
|
1958
2132
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1959
2133
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1960
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2134
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1961
2135
|
const document = await documentManager2.findOne(id, model, {
|
1962
2136
|
populate,
|
1963
2137
|
locale,
|
@@ -1972,14 +2146,14 @@ const collectionTypes = {
|
|
1972
2146
|
ctx.body = await strapiUtils.async.pipe(
|
1973
2147
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1974
2148
|
permissionChecker2.sanitizeOutput,
|
1975
|
-
(document2) =>
|
2149
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1976
2150
|
)(document);
|
1977
2151
|
},
|
1978
2152
|
async bulkDelete(ctx) {
|
1979
2153
|
const { userAbility } = ctx.state;
|
1980
2154
|
const { model } = ctx.params;
|
1981
2155
|
const { query, body } = ctx.request;
|
1982
|
-
const {
|
2156
|
+
const { documentIds } = body;
|
1983
2157
|
await validateBulkActionInput(body);
|
1984
2158
|
const documentManager2 = getService$1("document-manager");
|
1985
2159
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1987,14 +2161,22 @@ const collectionTypes = {
|
|
1987
2161
|
return ctx.forbidden();
|
1988
2162
|
}
|
1989
2163
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1990
|
-
const
|
1991
|
-
const
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
2164
|
+
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2165
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2166
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2167
|
+
populate,
|
2168
|
+
locale
|
2169
|
+
});
|
2170
|
+
if (documentLocales.length === 0) {
|
2171
|
+
return ctx.notFound();
|
2172
|
+
}
|
2173
|
+
for (const document of documentLocales) {
|
2174
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2175
|
+
return ctx.forbidden();
|
1995
2176
|
}
|
1996
|
-
}
|
1997
|
-
const
|
2177
|
+
}
|
2178
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2179
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1998
2180
|
ctx.body = { count };
|
1999
2181
|
},
|
2000
2182
|
async countDraftRelations(ctx) {
|
@@ -2007,7 +2189,7 @@ const collectionTypes = {
|
|
2007
2189
|
}
|
2008
2190
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2009
2191
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2010
|
-
const { locale, status
|
2192
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
2011
2193
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
2012
2194
|
if (!entity) {
|
2013
2195
|
return ctx.notFound();
|
@@ -2022,7 +2204,7 @@ const collectionTypes = {
|
|
2022
2204
|
},
|
2023
2205
|
async countManyEntriesDraftRelations(ctx) {
|
2024
2206
|
const { userAbility } = ctx.state;
|
2025
|
-
const ids = ctx.request.query.
|
2207
|
+
const ids = ctx.request.query.documentIds;
|
2026
2208
|
const locale = ctx.request.query.locale;
|
2027
2209
|
const { model } = ctx.params;
|
2028
2210
|
const documentManager2 = getService$1("document-manager");
|
@@ -2030,16 +2212,16 @@ const collectionTypes = {
|
|
2030
2212
|
if (permissionChecker2.cannot.read()) {
|
2031
2213
|
return ctx.forbidden();
|
2032
2214
|
}
|
2033
|
-
const
|
2215
|
+
const documents = await documentManager2.findMany(
|
2034
2216
|
{
|
2035
2217
|
filters: {
|
2036
|
-
|
2218
|
+
documentId: ids
|
2037
2219
|
},
|
2038
2220
|
locale
|
2039
2221
|
},
|
2040
2222
|
model
|
2041
2223
|
);
|
2042
|
-
if (!
|
2224
|
+
if (!documents) {
|
2043
2225
|
return ctx.notFound();
|
2044
2226
|
}
|
2045
2227
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2230,32 +2412,37 @@ const sanitizeMainField = (model, mainField, userAbility) => {
|
|
2230
2412
|
userAbility,
|
2231
2413
|
model: model.uid
|
2232
2414
|
});
|
2233
|
-
|
2415
|
+
const isMainFieldListable = isListable(model, mainField);
|
2416
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2417
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2234
2418
|
return "id";
|
2235
2419
|
}
|
2236
|
-
if (
|
2237
|
-
|
2238
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2239
|
-
userAbility,
|
2240
|
-
model: "plugin::users-permissions.user"
|
2241
|
-
});
|
2242
|
-
if (userPermissionChecker.can.read()) {
|
2243
|
-
return "name";
|
2244
|
-
}
|
2245
|
-
}
|
2246
|
-
return "id";
|
2420
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2421
|
+
return "name";
|
2247
2422
|
}
|
2248
2423
|
return mainField;
|
2249
2424
|
};
|
2250
|
-
const addStatusToRelations = async (
|
2251
|
-
if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.
|
2425
|
+
const addStatusToRelations = async (targetUid, relations2) => {
|
2426
|
+
if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
2252
2427
|
return relations2;
|
2253
2428
|
}
|
2254
2429
|
const documentMetadata2 = getService$1("document-metadata");
|
2255
|
-
|
2430
|
+
if (!relations2.length) {
|
2431
|
+
return relations2;
|
2432
|
+
}
|
2433
|
+
const firstRelation = relations2[0];
|
2434
|
+
const filters = {
|
2435
|
+
documentId: { $in: relations2.map((r) => r.documentId) },
|
2436
|
+
// NOTE: find the "opposite" status
|
2437
|
+
publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
|
2438
|
+
};
|
2439
|
+
const availableStatus = await strapi.query(targetUid).findMany({
|
2440
|
+
select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
|
2441
|
+
filters
|
2442
|
+
});
|
2256
2443
|
return relations2.map((relation) => {
|
2257
|
-
const availableStatuses =
|
2258
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2444
|
+
const availableStatuses = availableStatus.filter(
|
2445
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2259
2446
|
);
|
2260
2447
|
return {
|
2261
2448
|
...relation,
|
@@ -2276,11 +2463,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2276
2463
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2277
2464
|
const isSourceLocalized = isLocalized(sourceModel);
|
2278
2465
|
const isTargetLocalized = isLocalized(targetModel);
|
2279
|
-
let validatedLocale = locale;
|
2280
|
-
if (!targetModel || !isTargetLocalized)
|
2281
|
-
validatedLocale = void 0;
|
2282
2466
|
return {
|
2283
|
-
locale
|
2467
|
+
locale,
|
2284
2468
|
isSourceLocalized,
|
2285
2469
|
isTargetLocalized
|
2286
2470
|
};
|
@@ -2383,7 +2567,7 @@ const relations = {
|
|
2383
2567
|
attribute,
|
2384
2568
|
fieldsToSelect,
|
2385
2569
|
mainField,
|
2386
|
-
source: { schema: sourceSchema },
|
2570
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2387
2571
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2388
2572
|
sourceSchema,
|
2389
2573
|
targetSchema,
|
@@ -2405,7 +2589,8 @@ const relations = {
|
|
2405
2589
|
fieldsToSelect,
|
2406
2590
|
mainField,
|
2407
2591
|
source: {
|
2408
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2592
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2593
|
+
isLocalized: isSourceLocalized
|
2409
2594
|
},
|
2410
2595
|
target: {
|
2411
2596
|
schema: { uid: targetUid },
|
@@ -2443,12 +2628,16 @@ const relations = {
|
|
2443
2628
|
} else {
|
2444
2629
|
where.id = id;
|
2445
2630
|
}
|
2446
|
-
|
2447
|
-
|
2631
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2632
|
+
if (!fp.isEmpty(publishedAt)) {
|
2633
|
+
where[`${alias}.published_at`] = publishedAt;
|
2448
2634
|
}
|
2449
|
-
if (
|
2635
|
+
if (isTargetLocalized && locale) {
|
2450
2636
|
where[`${alias}.locale`] = locale;
|
2451
2637
|
}
|
2638
|
+
if (isSourceLocalized && locale) {
|
2639
|
+
where.locale = locale;
|
2640
|
+
}
|
2452
2641
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2453
2642
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2454
2643
|
}
|
@@ -2466,7 +2655,8 @@ const relations = {
|
|
2466
2655
|
id: { $notIn: fp.uniq(idsToOmit) }
|
2467
2656
|
});
|
2468
2657
|
}
|
2469
|
-
const
|
2658
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2659
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2470
2660
|
ctx.body = {
|
2471
2661
|
...res,
|
2472
2662
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2481,29 +2671,39 @@ const relations = {
|
|
2481
2671
|
attribute,
|
2482
2672
|
targetField,
|
2483
2673
|
fieldsToSelect,
|
2484
|
-
|
2485
|
-
|
2486
|
-
}
|
2487
|
-
target: {
|
2488
|
-
schema: { uid: targetUid }
|
2489
|
-
}
|
2674
|
+
status,
|
2675
|
+
source: { schema: sourceSchema },
|
2676
|
+
target: { schema: targetSchema }
|
2490
2677
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2678
|
+
const { uid: sourceUid } = sourceSchema;
|
2679
|
+
const { uid: targetUid } = targetSchema;
|
2491
2680
|
const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
|
2492
2681
|
const dbQuery = strapi.db.query(sourceUid);
|
2493
2682
|
const loadRelations = strapiUtils.relations.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
|
2683
|
+
const filters = {};
|
2684
|
+
if (sourceSchema?.options?.draftAndPublish) {
|
2685
|
+
if (targetSchema?.options?.draftAndPublish) {
|
2686
|
+
if (status === "published") {
|
2687
|
+
filters.publishedAt = { $notNull: true };
|
2688
|
+
} else {
|
2689
|
+
filters.publishedAt = { $null: true };
|
2690
|
+
}
|
2691
|
+
}
|
2692
|
+
} else if (targetSchema?.options?.draftAndPublish) {
|
2693
|
+
filters.publishedAt = { $null: true };
|
2694
|
+
}
|
2494
2695
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2495
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2696
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2496
2697
|
ordering: "desc",
|
2497
2698
|
page: ctx.request.query.page,
|
2498
|
-
pageSize: ctx.request.query.pageSize
|
2699
|
+
pageSize: ctx.request.query.pageSize,
|
2700
|
+
filters
|
2499
2701
|
});
|
2500
2702
|
const loadedIds = res.results.map((item) => item.id);
|
2501
2703
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2502
2704
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2503
2705
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2504
|
-
ordering: "desc"
|
2505
|
-
page: ctx.request.query.page,
|
2506
|
-
pageSize: ctx.request.query.pageSize
|
2706
|
+
ordering: "desc"
|
2507
2707
|
});
|
2508
2708
|
const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
|
2509
2709
|
ctx.body = {
|
@@ -2535,7 +2735,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2535
2735
|
throw new strapiUtils.errors.ForbiddenError();
|
2536
2736
|
}
|
2537
2737
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2538
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2738
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2539
2739
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2540
2740
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2541
2741
|
// Find the first document to check if it exists
|
@@ -2572,12 +2772,11 @@ const singleTypes = {
|
|
2572
2772
|
const { model } = ctx.params;
|
2573
2773
|
const { query = {} } = ctx.request;
|
2574
2774
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2575
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2576
2775
|
if (permissionChecker2.cannot.read()) {
|
2577
2776
|
return ctx.forbidden();
|
2578
2777
|
}
|
2579
2778
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2580
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2779
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2581
2780
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2582
2781
|
if (!version) {
|
2583
2782
|
if (permissionChecker2.cannot.create()) {
|
@@ -2587,9 +2786,11 @@ const singleTypes = {
|
|
2587
2786
|
if (!document) {
|
2588
2787
|
return ctx.notFound();
|
2589
2788
|
}
|
2590
|
-
const { meta } = await
|
2789
|
+
const { meta } = await formatDocumentWithMetadata(
|
2790
|
+
permissionChecker2,
|
2591
2791
|
model,
|
2592
|
-
|
2792
|
+
// @ts-expect-error - fix types
|
2793
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2593
2794
|
{ availableLocales: true, availableStatus: false }
|
2594
2795
|
);
|
2595
2796
|
ctx.body = { data: {}, meta };
|
@@ -2599,16 +2800,15 @@ const singleTypes = {
|
|
2599
2800
|
return ctx.forbidden();
|
2600
2801
|
}
|
2601
2802
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2602
|
-
ctx.body = await
|
2803
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2603
2804
|
},
|
2604
2805
|
async createOrUpdate(ctx) {
|
2605
2806
|
const { userAbility } = ctx.state;
|
2606
2807
|
const { model } = ctx.params;
|
2607
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2608
2808
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2609
2809
|
const document = await createOrUpdateDocument(ctx);
|
2610
2810
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2611
|
-
ctx.body = await
|
2811
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2612
2812
|
},
|
2613
2813
|
async delete(ctx) {
|
2614
2814
|
const { userAbility } = ctx.state;
|
@@ -2621,7 +2821,7 @@ const singleTypes = {
|
|
2621
2821
|
}
|
2622
2822
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2623
2823
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2624
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2824
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2625
2825
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2626
2826
|
populate,
|
2627
2827
|
locale
|
@@ -2644,7 +2844,6 @@ const singleTypes = {
|
|
2644
2844
|
const { model } = ctx.params;
|
2645
2845
|
const { query = {} } = ctx.request;
|
2646
2846
|
const documentManager2 = getService$1("document-manager");
|
2647
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2648
2847
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2649
2848
|
if (permissionChecker2.cannot.publish()) {
|
2650
2849
|
return ctx.forbidden();
|
@@ -2659,11 +2858,12 @@ const singleTypes = {
|
|
2659
2858
|
if (permissionChecker2.cannot.publish(document)) {
|
2660
2859
|
throw new strapiUtils.errors.ForbiddenError();
|
2661
2860
|
}
|
2662
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2663
|
-
|
2861
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2862
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2863
|
+
return publishResult.at(0);
|
2664
2864
|
});
|
2665
2865
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2666
|
-
ctx.body = await
|
2866
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2667
2867
|
},
|
2668
2868
|
async unpublish(ctx) {
|
2669
2869
|
const { userAbility } = ctx.state;
|
@@ -2673,7 +2873,6 @@ const singleTypes = {
|
|
2673
2873
|
query = {}
|
2674
2874
|
} = ctx.request;
|
2675
2875
|
const documentManager2 = getService$1("document-manager");
|
2676
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2677
2876
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2678
2877
|
if (permissionChecker2.cannot.unpublish()) {
|
2679
2878
|
return ctx.forbidden();
|
@@ -2682,7 +2881,7 @@ const singleTypes = {
|
|
2682
2881
|
return ctx.forbidden();
|
2683
2882
|
}
|
2684
2883
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2685
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2884
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2686
2885
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2687
2886
|
if (!document) {
|
2688
2887
|
return ctx.notFound();
|
@@ -2700,7 +2899,7 @@ const singleTypes = {
|
|
2700
2899
|
ctx.body = await strapiUtils.async.pipe(
|
2701
2900
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2702
2901
|
permissionChecker2.sanitizeOutput,
|
2703
|
-
(document2) =>
|
2902
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2704
2903
|
)(document);
|
2705
2904
|
});
|
2706
2905
|
},
|
@@ -2709,13 +2908,12 @@ const singleTypes = {
|
|
2709
2908
|
const { model } = ctx.params;
|
2710
2909
|
const { body, query = {} } = ctx.request;
|
2711
2910
|
const documentManager2 = getService$1("document-manager");
|
2712
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2713
2911
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2714
2912
|
if (permissionChecker2.cannot.discard()) {
|
2715
2913
|
return ctx.forbidden();
|
2716
2914
|
}
|
2717
2915
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2718
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2916
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2719
2917
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2720
2918
|
if (!document) {
|
2721
2919
|
return ctx.notFound();
|
@@ -2726,7 +2924,7 @@ const singleTypes = {
|
|
2726
2924
|
ctx.body = await strapiUtils.async.pipe(
|
2727
2925
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2728
2926
|
permissionChecker2.sanitizeOutput,
|
2729
|
-
(document2) =>
|
2927
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2730
2928
|
)(document);
|
2731
2929
|
},
|
2732
2930
|
async countDraftRelations(ctx) {
|
@@ -2735,7 +2933,7 @@ const singleTypes = {
|
|
2735
2933
|
const { query } = ctx.request;
|
2736
2934
|
const documentManager2 = getService$1("document-manager");
|
2737
2935
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2738
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2936
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2739
2937
|
if (permissionChecker2.cannot.read()) {
|
2740
2938
|
return ctx.forbidden();
|
2741
2939
|
}
|
@@ -2756,7 +2954,7 @@ const uid$1 = {
|
|
2756
2954
|
async generateUID(ctx) {
|
2757
2955
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2758
2956
|
const { query = {} } = ctx.request;
|
2759
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2957
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2760
2958
|
await validateUIDField(contentTypeUID, field);
|
2761
2959
|
const uidService = getService$1("uid");
|
2762
2960
|
ctx.body = {
|
@@ -2768,7 +2966,7 @@ const uid$1 = {
|
|
2768
2966
|
ctx.request.body
|
2769
2967
|
);
|
2770
2968
|
const { query = {} } = ctx.request;
|
2771
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2969
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2772
2970
|
await validateUIDField(contentTypeUID, field);
|
2773
2971
|
const uidService = getService$1("uid");
|
2774
2972
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -2791,7 +2989,8 @@ const controllers = {
|
|
2791
2989
|
relations,
|
2792
2990
|
"single-types": singleTypes,
|
2793
2991
|
uid: uid$1,
|
2794
|
-
...history.controllers ? history.controllers : {}
|
2992
|
+
...history.controllers ? history.controllers : {},
|
2993
|
+
...preview.controllers ? preview.controllers : {}
|
2795
2994
|
};
|
2796
2995
|
const keys = {
|
2797
2996
|
CONFIGURATION: "configuration"
|
@@ -3411,12 +3610,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3411
3610
|
ability: userAbility,
|
3412
3611
|
model
|
3413
3612
|
});
|
3414
|
-
const
|
3613
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3614
|
+
const toSubject = (entity) => {
|
3615
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3616
|
+
};
|
3415
3617
|
const can = (action, entity, field) => {
|
3416
|
-
|
3618
|
+
const subject = toSubject(entity);
|
3619
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3620
|
+
return (
|
3621
|
+
// Test the original action to see if it passes
|
3622
|
+
userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
|
3623
|
+
aliases.some((alias) => userAbility.can(alias, subject, field))
|
3624
|
+
);
|
3417
3625
|
};
|
3418
3626
|
const cannot = (action, entity, field) => {
|
3419
|
-
|
3627
|
+
const subject = toSubject(entity);
|
3628
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3629
|
+
return (
|
3630
|
+
// Test both the original action
|
3631
|
+
userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
|
3632
|
+
aliases.every((alias) => userAbility.cannot(alias, subject, field))
|
3633
|
+
);
|
3420
3634
|
};
|
3421
3635
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3422
3636
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3559,7 +3773,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3559
3773
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3560
3774
|
}
|
3561
3775
|
});
|
3562
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils__default.default.contentTypes;
|
3776
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils__default.default.contentTypes;
|
3563
3777
|
const { isAnyToMany } = strapiUtils__default.default.relations;
|
3564
3778
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils__default.default.contentTypes.constants;
|
3565
3779
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3650,6 +3864,42 @@ const getDeepPopulate = (uid2, {
|
|
3650
3864
|
{}
|
3651
3865
|
);
|
3652
3866
|
};
|
3867
|
+
const getValidatableFieldsPopulate = (uid2, {
|
3868
|
+
initialPopulate = {},
|
3869
|
+
countMany = false,
|
3870
|
+
countOne = false,
|
3871
|
+
maxLevel = Infinity
|
3872
|
+
} = {}, level = 1) => {
|
3873
|
+
if (level > maxLevel) {
|
3874
|
+
return {};
|
3875
|
+
}
|
3876
|
+
const model = strapi.getModel(uid2);
|
3877
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3878
|
+
if (!getDoesAttributeRequireValidation(attribute)) {
|
3879
|
+
return populateAcc;
|
3880
|
+
}
|
3881
|
+
if (isScalarAttribute(attribute)) {
|
3882
|
+
return fp.merge(populateAcc, {
|
3883
|
+
[attributeName]: true
|
3884
|
+
});
|
3885
|
+
}
|
3886
|
+
return fp.merge(
|
3887
|
+
populateAcc,
|
3888
|
+
getPopulateFor(
|
3889
|
+
attributeName,
|
3890
|
+
model,
|
3891
|
+
{
|
3892
|
+
// @ts-expect-error - improve types
|
3893
|
+
initialPopulate: initialPopulate?.[attributeName],
|
3894
|
+
countMany,
|
3895
|
+
countOne,
|
3896
|
+
maxLevel
|
3897
|
+
},
|
3898
|
+
level
|
3899
|
+
)
|
3900
|
+
);
|
3901
|
+
}, {});
|
3902
|
+
};
|
3653
3903
|
const getDeepPopulateDraftCount = (uid2) => {
|
3654
3904
|
const model = strapi.getModel(uid2);
|
3655
3905
|
let hasRelations = false;
|
@@ -3657,6 +3907,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3657
3907
|
const attribute = model.attributes[attributeName];
|
3658
3908
|
switch (attribute.type) {
|
3659
3909
|
case "relation": {
|
3910
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
3911
|
+
if (isMorphRelation) {
|
3912
|
+
break;
|
3913
|
+
}
|
3660
3914
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3661
3915
|
populateAcc[attributeName] = {
|
3662
3916
|
count: true,
|
@@ -3671,22 +3925,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3671
3925
|
attribute.component
|
3672
3926
|
);
|
3673
3927
|
if (childHasRelations) {
|
3674
|
-
populateAcc[attributeName] = {
|
3928
|
+
populateAcc[attributeName] = {
|
3929
|
+
populate: populate2
|
3930
|
+
};
|
3675
3931
|
hasRelations = true;
|
3676
3932
|
}
|
3677
3933
|
break;
|
3678
3934
|
}
|
3679
3935
|
case "dynamiczone": {
|
3680
|
-
const
|
3681
|
-
const { populate:
|
3682
|
-
if (
|
3936
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
3937
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
3938
|
+
if (componentHasRelations) {
|
3683
3939
|
hasRelations = true;
|
3684
|
-
return
|
3940
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3685
3941
|
}
|
3686
3942
|
return acc;
|
3687
3943
|
}, {});
|
3688
|
-
if (!fp.isEmpty(
|
3689
|
-
populateAcc[attributeName] = {
|
3944
|
+
if (!fp.isEmpty(dzPopulateFragment)) {
|
3945
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3690
3946
|
}
|
3691
3947
|
break;
|
3692
3948
|
}
|
@@ -3878,41 +4134,72 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3878
4134
|
"updatedBy",
|
3879
4135
|
"status"
|
3880
4136
|
];
|
3881
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
4137
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
4138
|
+
"id",
|
4139
|
+
"locale",
|
4140
|
+
"updatedAt",
|
4141
|
+
"createdAt",
|
4142
|
+
"status",
|
4143
|
+
"publishedAt",
|
4144
|
+
"documentId"
|
4145
|
+
];
|
3882
4146
|
const CONTENT_MANAGER_STATUS = {
|
3883
4147
|
PUBLISHED: "published",
|
3884
4148
|
DRAFT: "draft",
|
3885
4149
|
MODIFIED: "modified"
|
3886
4150
|
};
|
3887
|
-
const
|
3888
|
-
if (!
|
4151
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
4152
|
+
if (!version || !version.updatedAt) {
|
3889
4153
|
return false;
|
3890
4154
|
}
|
3891
|
-
const
|
3892
|
-
const
|
3893
|
-
|
3894
|
-
return difference <= threshold;
|
4155
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
4156
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
4157
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3895
4158
|
};
|
3896
4159
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3897
4160
|
/**
|
3898
4161
|
* Returns available locales of a document for the current status
|
3899
4162
|
*/
|
3900
|
-
getAvailableLocales(uid2, version, allVersions) {
|
4163
|
+
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3901
4164
|
const versionsByLocale = fp.groupBy("locale", allVersions);
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
4165
|
+
if (version.locale) {
|
4166
|
+
delete versionsByLocale[version.locale];
|
4167
|
+
}
|
4168
|
+
const model = strapi2.getModel(uid2);
|
4169
|
+
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
4170
|
+
const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
|
4171
|
+
({ key }, { remove }) => {
|
4172
|
+
if (keysToKeep.includes(key)) {
|
4173
|
+
return;
|
4174
|
+
}
|
4175
|
+
remove(key);
|
4176
|
+
},
|
4177
|
+
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
4178
|
+
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
4179
|
+
localeVersion
|
4180
|
+
);
|
4181
|
+
const mappingResult = await strapiUtils.async.map(
|
4182
|
+
Object.values(versionsByLocale),
|
4183
|
+
async (localeVersions) => {
|
4184
|
+
const mappedLocaleVersions = await strapiUtils.async.map(
|
4185
|
+
localeVersions,
|
4186
|
+
traversalFunction
|
4187
|
+
);
|
4188
|
+
if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
|
4189
|
+
return mappedLocaleVersions[0];
|
4190
|
+
}
|
4191
|
+
const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
|
4192
|
+
const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
|
4193
|
+
if (!draftVersion) {
|
4194
|
+
return;
|
4195
|
+
}
|
4196
|
+
return {
|
4197
|
+
...draftVersion,
|
4198
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4199
|
+
};
|
3906
4200
|
}
|
3907
|
-
|
3908
|
-
|
3909
|
-
if (!draftVersion)
|
3910
|
-
return;
|
3911
|
-
return {
|
3912
|
-
...fp.pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
|
3913
|
-
status: this.getStatus(draftVersion, otherVersions)
|
3914
|
-
};
|
3915
|
-
}).filter(Boolean);
|
4201
|
+
);
|
4202
|
+
return mappingResult.filter(Boolean);
|
3916
4203
|
},
|
3917
4204
|
/**
|
3918
4205
|
* Returns available status of a document for the current locale
|
@@ -3950,26 +4237,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3950
4237
|
});
|
3951
4238
|
},
|
3952
4239
|
getStatus(version, otherDocumentStatuses) {
|
3953
|
-
|
3954
|
-
|
3955
|
-
|
4240
|
+
let draftVersion;
|
4241
|
+
let publishedVersion;
|
4242
|
+
if (version.publishedAt) {
|
4243
|
+
publishedVersion = version;
|
4244
|
+
} else {
|
4245
|
+
draftVersion = version;
|
3956
4246
|
}
|
3957
|
-
|
3958
|
-
|
3959
|
-
|
3960
|
-
|
3961
|
-
|
4247
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4248
|
+
if (otherVersion?.publishedAt) {
|
4249
|
+
publishedVersion = otherVersion;
|
4250
|
+
} else if (otherVersion) {
|
4251
|
+
draftVersion = otherVersion;
|
3962
4252
|
}
|
3963
|
-
if (
|
4253
|
+
if (!draftVersion)
|
3964
4254
|
return CONTENT_MANAGER_STATUS.PUBLISHED;
|
3965
|
-
|
3966
|
-
|
4255
|
+
if (!publishedVersion)
|
4256
|
+
return CONTENT_MANAGER_STATUS.DRAFT;
|
4257
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4258
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3967
4259
|
},
|
4260
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4261
|
+
// We could refactor this so the locales are only loaded when they're
|
4262
|
+
// needed. e.g. in the bulk locale action modal.
|
3968
4263
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4264
|
+
const populate = getValidatableFieldsPopulate(uid2);
|
3969
4265
|
const versions = await strapi2.db.query(uid2).findMany({
|
3970
4266
|
where: { documentId: version.documentId },
|
3971
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
3972
4267
|
populate: {
|
4268
|
+
// Populate only fields that require validation for bulk locale actions
|
4269
|
+
...populate,
|
4270
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3973
4271
|
createdBy: {
|
3974
4272
|
select: ["id", "firstname", "lastname", "email"]
|
3975
4273
|
},
|
@@ -3978,7 +4276,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3978
4276
|
}
|
3979
4277
|
}
|
3980
4278
|
});
|
3981
|
-
const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
|
4279
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
|
3982
4280
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3983
4281
|
return {
|
3984
4282
|
availableLocales: availableLocalesResult,
|
@@ -3991,8 +4289,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3991
4289
|
* - Available status of the document for the current locale
|
3992
4290
|
*/
|
3993
4291
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3994
|
-
if (!document)
|
3995
|
-
return
|
4292
|
+
if (!document) {
|
4293
|
+
return {
|
4294
|
+
data: document,
|
4295
|
+
meta: {
|
4296
|
+
availableLocales: [],
|
4297
|
+
availableStatus: []
|
4298
|
+
}
|
4299
|
+
};
|
4300
|
+
}
|
3996
4301
|
const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
|
3997
4302
|
if (!hasDraftAndPublish) {
|
3998
4303
|
opts.availableStatus = false;
|
@@ -4042,26 +4347,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
4042
4347
|
}, 0);
|
4043
4348
|
};
|
4044
4349
|
const { ApplicationError } = strapiUtils.errors;
|
4045
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
4046
4350
|
const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
|
4047
4351
|
const omitPublishedAtField = fp.omit(PUBLISHED_AT_ATTRIBUTE);
|
4048
4352
|
const omitIdField = fp.omit("id");
|
4049
|
-
const emitEvent = async (uid2, event, document) => {
|
4050
|
-
const modelDef = strapi.getModel(uid2);
|
4051
|
-
const sanitizedDocument = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
|
4052
|
-
{
|
4053
|
-
schema: modelDef,
|
4054
|
-
getModel(uid22) {
|
4055
|
-
return strapi.getModel(uid22);
|
4056
|
-
}
|
4057
|
-
},
|
4058
|
-
document
|
4059
|
-
);
|
4060
|
-
strapi.eventHub.emit(event, {
|
4061
|
-
model: modelDef.modelName,
|
4062
|
-
entry: sanitizedDocument
|
4063
|
-
});
|
4064
|
-
};
|
4065
4353
|
const documentManager = ({ strapi: strapi2 }) => {
|
4066
4354
|
return {
|
4067
4355
|
async findOne(id, uid2, opts = {}) {
|
@@ -4080,6 +4368,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4080
4368
|
} else if (opts.locale && opts.locale !== "*") {
|
4081
4369
|
where.locale = opts.locale;
|
4082
4370
|
}
|
4371
|
+
if (typeof opts.isPublished === "boolean") {
|
4372
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4373
|
+
}
|
4083
4374
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4084
4375
|
},
|
4085
4376
|
async findMany(opts, uid2) {
|
@@ -4113,10 +4404,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4113
4404
|
async clone(id, body, uid2) {
|
4114
4405
|
const populate = await buildDeepPopulate(uid2);
|
4115
4406
|
const params = {
|
4116
|
-
data:
|
4117
|
-
...omitIdField(body),
|
4118
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4119
|
-
},
|
4407
|
+
data: omitIdField(body),
|
4120
4408
|
populate
|
4121
4409
|
};
|
4122
4410
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4142,70 +4430,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4142
4430
|
return {};
|
4143
4431
|
},
|
4144
4432
|
// FIXME: handle relations
|
4145
|
-
async deleteMany(
|
4146
|
-
const
|
4147
|
-
|
4148
|
-
|
4149
|
-
}
|
4150
|
-
return { count: docs.length };
|
4433
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4434
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4435
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4436
|
+
});
|
4437
|
+
return { count: deletedEntries.length };
|
4151
4438
|
},
|
4152
4439
|
async publish(id, uid2, opts = {}) {
|
4153
4440
|
const populate = await buildDeepPopulate(uid2);
|
4154
4441
|
const params = { ...opts, populate };
|
4155
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4442
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4156
4443
|
},
|
4157
|
-
async publishMany(
|
4158
|
-
|
4159
|
-
|
4160
|
-
|
4161
|
-
|
4162
|
-
|
4163
|
-
|
4164
|
-
strapi2.getModel(uid2),
|
4165
|
-
document,
|
4166
|
-
void 0,
|
4167
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4168
|
-
document
|
4169
|
-
);
|
4170
|
-
})
|
4171
|
-
);
|
4172
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4173
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4174
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4175
|
-
const populate = await buildDeepPopulate(uid2);
|
4176
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4177
|
-
where: filters,
|
4178
|
-
data
|
4179
|
-
});
|
4180
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4181
|
-
where: filters,
|
4182
|
-
populate
|
4444
|
+
async publishMany(uid2, documentIds, locale) {
|
4445
|
+
return strapi2.db.transaction(async () => {
|
4446
|
+
const results = await Promise.all(
|
4447
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4448
|
+
);
|
4449
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4450
|
+
return publishedEntitiesCount;
|
4183
4451
|
});
|
4184
|
-
await Promise.all(
|
4185
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4186
|
-
);
|
4187
|
-
return publishedEntitiesCount;
|
4188
4452
|
},
|
4189
|
-
async unpublishMany(
|
4190
|
-
|
4191
|
-
return
|
4192
|
-
|
4193
|
-
|
4194
|
-
|
4195
|
-
|
4196
|
-
const populate = await buildDeepPopulate(uid2);
|
4197
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4198
|
-
where: filters,
|
4199
|
-
data
|
4200
|
-
});
|
4201
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4202
|
-
where: filters,
|
4203
|
-
populate
|
4453
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4454
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4455
|
+
return Promise.all(
|
4456
|
+
documentIds.map(
|
4457
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4458
|
+
)
|
4459
|
+
);
|
4204
4460
|
});
|
4205
|
-
|
4206
|
-
|
4207
|
-
);
|
4208
|
-
return unpublishedEntitiesCount;
|
4461
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4462
|
+
return { count: unpublishedEntitiesCount };
|
4209
4463
|
},
|
4210
4464
|
async unpublish(id, uid2, opts = {}) {
|
4211
4465
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4230,16 +4484,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4230
4484
|
}
|
4231
4485
|
return sumDraftCounts(document, uid2);
|
4232
4486
|
},
|
4233
|
-
async countManyEntriesDraftRelations(
|
4487
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4234
4488
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4235
4489
|
if (!hasRelations) {
|
4236
4490
|
return 0;
|
4237
4491
|
}
|
4492
|
+
let localeFilter = {};
|
4493
|
+
if (locale) {
|
4494
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4495
|
+
}
|
4238
4496
|
const entities = await strapi2.db.query(uid2).findMany({
|
4239
4497
|
populate,
|
4240
4498
|
where: {
|
4241
|
-
|
4242
|
-
...
|
4499
|
+
documentId: { $in: documentIds },
|
4500
|
+
...localeFilter
|
4243
4501
|
}
|
4244
4502
|
});
|
4245
4503
|
const totalNumberDraftRelations = entities.reduce(
|
@@ -4262,7 +4520,8 @@ const services = {
|
|
4262
4520
|
permission,
|
4263
4521
|
"populate-builder": populateBuilder$1,
|
4264
4522
|
uid,
|
4265
|
-
...history.services ? history.services : {}
|
4523
|
+
...history.services ? history.services : {},
|
4524
|
+
...preview.services ? preview.services : {}
|
4266
4525
|
};
|
4267
4526
|
const index = () => {
|
4268
4527
|
return {
|