@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.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1,
|
2
|
-
import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy
|
1
|
+
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, traverseEntity, pagination } from "@strapi/utils";
|
2
|
+
import { pick, omit, difference, castArray, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
|
3
3
|
import "@strapi/types";
|
4
4
|
import * as yup from "yup";
|
5
5
|
import { scheduleJob } from "node-schedule";
|
@@ -95,7 +95,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
95
95
|
}
|
96
96
|
};
|
97
97
|
};
|
98
|
-
const controllers$
|
98
|
+
const controllers$2 = {
|
99
99
|
"history-version": createHistoryVersionController
|
100
100
|
/**
|
101
101
|
* Casting is needed because the types aren't aware that Strapi supports
|
@@ -173,7 +173,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
173
173
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
174
174
|
};
|
175
175
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
176
|
+
const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
|
176
177
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
178
|
+
const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
|
177
179
|
const getLocaleDictionary = async () => {
|
178
180
|
if (!localesService)
|
179
181
|
return {};
|
@@ -200,20 +202,25 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
200
202
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
201
203
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
202
204
|
};
|
203
|
-
const getDeepPopulate2 = (uid2) => {
|
205
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
204
206
|
const model = strapi2.getModel(uid2);
|
205
207
|
const attributes = Object.entries(model.attributes);
|
208
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
206
209
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
207
210
|
switch (attribute.type) {
|
208
211
|
case "relation": {
|
212
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
213
|
+
if (isMorphRelation) {
|
214
|
+
break;
|
215
|
+
}
|
209
216
|
const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
|
210
217
|
if (isVisible2) {
|
211
|
-
acc[attributeName] = {
|
218
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
212
219
|
}
|
213
220
|
break;
|
214
221
|
}
|
215
222
|
case "media": {
|
216
|
-
acc[attributeName] = {
|
223
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
217
224
|
break;
|
218
225
|
}
|
219
226
|
case "component": {
|
@@ -286,6 +293,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
286
293
|
getRelationRestoreValue,
|
287
294
|
getMediaRestoreValue,
|
288
295
|
getDefaultLocale,
|
296
|
+
isLocalizedContentType,
|
289
297
|
getLocaleDictionary,
|
290
298
|
getRetentionDays,
|
291
299
|
getVersionStatus,
|
@@ -308,7 +316,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
308
316
|
});
|
309
317
|
},
|
310
318
|
async findVersionsPage(params) {
|
311
|
-
const
|
319
|
+
const model = strapi2.getModel(params.query.contentType);
|
320
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
321
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
322
|
+
let locale = null;
|
323
|
+
if (isLocalizedContentType) {
|
324
|
+
locale = params.query.locale || defaultLocale;
|
325
|
+
}
|
312
326
|
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
313
327
|
query.findPage({
|
314
328
|
...params.query,
|
@@ -353,7 +367,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
353
367
|
if (userToPopulate == null) {
|
354
368
|
return null;
|
355
369
|
}
|
356
|
-
return strapi2.query("admin::user").findOne({
|
370
|
+
return strapi2.query("admin::user").findOne({
|
371
|
+
where: {
|
372
|
+
...userToPopulate.id ? { id: userToPopulate.id } : {},
|
373
|
+
...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
|
374
|
+
}
|
375
|
+
});
|
357
376
|
})
|
358
377
|
);
|
359
378
|
return {
|
@@ -464,13 +483,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
464
483
|
}
|
465
484
|
};
|
466
485
|
};
|
486
|
+
const shouldCreateHistoryVersion = (context) => {
|
487
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
488
|
+
return false;
|
489
|
+
}
|
490
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
491
|
+
return false;
|
492
|
+
}
|
493
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
494
|
+
return false;
|
495
|
+
}
|
496
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
497
|
+
return false;
|
498
|
+
}
|
499
|
+
return true;
|
500
|
+
};
|
501
|
+
const getSchemas = (uid2) => {
|
502
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
503
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
504
|
+
(currentComponentSchemas, key) => {
|
505
|
+
const fieldSchema = attributesSchema[key];
|
506
|
+
if (fieldSchema.type === "component") {
|
507
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
508
|
+
return {
|
509
|
+
...currentComponentSchemas,
|
510
|
+
[fieldSchema.component]: componentSchema
|
511
|
+
};
|
512
|
+
}
|
513
|
+
return currentComponentSchemas;
|
514
|
+
},
|
515
|
+
{}
|
516
|
+
);
|
517
|
+
return {
|
518
|
+
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
519
|
+
componentsSchemas
|
520
|
+
};
|
521
|
+
};
|
467
522
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
468
523
|
const state = {
|
469
524
|
deleteExpiredJob: null,
|
470
525
|
isInitialized: false
|
471
526
|
};
|
472
|
-
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
473
|
-
const historyService = getService(strapi2, "history");
|
474
527
|
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
475
528
|
return {
|
476
529
|
async bootstrap() {
|
@@ -478,60 +531,53 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
478
531
|
return;
|
479
532
|
}
|
480
533
|
strapi2.documents.use(async (context, next) => {
|
481
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
482
|
-
return next();
|
483
|
-
}
|
484
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
485
|
-
return next();
|
486
|
-
}
|
487
|
-
const contentTypeUid = context.contentType.uid;
|
488
|
-
if (!contentTypeUid.startsWith("api::")) {
|
489
|
-
return next();
|
490
|
-
}
|
491
534
|
const result = await next();
|
492
|
-
|
535
|
+
if (!shouldCreateHistoryVersion(context)) {
|
536
|
+
return result;
|
537
|
+
}
|
538
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
493
539
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
494
|
-
const
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
540
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
541
|
+
if (!locales.length) {
|
542
|
+
return result;
|
543
|
+
}
|
544
|
+
const uid2 = context.contentType.uid;
|
545
|
+
const schemas = getSchemas(uid2);
|
546
|
+
const model = strapi2.getModel(uid2);
|
547
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
548
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
549
|
+
where: {
|
550
|
+
documentId,
|
551
|
+
...isLocalizedContentType ? { locale: { $in: locales } } : {},
|
552
|
+
...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
|
553
|
+
},
|
554
|
+
populate: serviceUtils.getDeepPopulate(
|
555
|
+
uid2,
|
556
|
+
true
|
557
|
+
/* use database syntax */
|
558
|
+
)
|
499
559
|
});
|
500
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
501
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
502
|
-
const componentsSchemas = Object.keys(
|
503
|
-
attributesSchema
|
504
|
-
).reduce((currentComponentSchemas, key) => {
|
505
|
-
const fieldSchema = attributesSchema[key];
|
506
|
-
if (fieldSchema.type === "component") {
|
507
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
508
|
-
return {
|
509
|
-
...currentComponentSchemas,
|
510
|
-
[fieldSchema.component]: componentSchema
|
511
|
-
};
|
512
|
-
}
|
513
|
-
return currentComponentSchemas;
|
514
|
-
}, {});
|
515
560
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
516
|
-
onCommit(() => {
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
561
|
+
onCommit(async () => {
|
562
|
+
for (const entry of localeEntries) {
|
563
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
564
|
+
await getService(strapi2, "history").createVersion({
|
565
|
+
contentType: uid2,
|
566
|
+
data: omit(FIELDS_TO_IGNORE, entry),
|
567
|
+
relatedDocumentId: documentId,
|
568
|
+
locale: entry.locale,
|
569
|
+
status,
|
570
|
+
...schemas
|
571
|
+
});
|
572
|
+
}
|
526
573
|
});
|
527
574
|
});
|
528
575
|
return result;
|
529
576
|
});
|
530
|
-
const retentionDays = serviceUtils.getRetentionDays();
|
531
577
|
state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
|
532
|
-
const retentionDaysInMilliseconds =
|
578
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
533
579
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
534
|
-
query.deleteMany({
|
580
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
535
581
|
where: {
|
536
582
|
created_at: {
|
537
583
|
$lt: expirationDate.toISOString()
|
@@ -548,17 +594,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
548
594
|
}
|
549
595
|
};
|
550
596
|
};
|
551
|
-
const services$
|
597
|
+
const services$2 = {
|
552
598
|
history: createHistoryService,
|
553
599
|
lifecycles: createLifecyclesService
|
554
600
|
};
|
555
|
-
const info = { pluginName: "content-manager", type: "admin" };
|
601
|
+
const info$1 = { pluginName: "content-manager", type: "admin" };
|
556
602
|
const historyVersionRouter = {
|
557
603
|
type: "admin",
|
558
604
|
routes: [
|
559
605
|
{
|
560
606
|
method: "GET",
|
561
|
-
info,
|
607
|
+
info: info$1,
|
562
608
|
path: "/history-versions",
|
563
609
|
handler: "history-version.findMany",
|
564
610
|
config: {
|
@@ -567,7 +613,7 @@ const historyVersionRouter = {
|
|
567
613
|
},
|
568
614
|
{
|
569
615
|
method: "PUT",
|
570
|
-
info,
|
616
|
+
info: info$1,
|
571
617
|
path: "/history-versions/:versionId/restore",
|
572
618
|
handler: "history-version.restoreVersion",
|
573
619
|
config: {
|
@@ -576,7 +622,7 @@ const historyVersionRouter = {
|
|
576
622
|
}
|
577
623
|
]
|
578
624
|
};
|
579
|
-
const routes$
|
625
|
+
const routes$2 = {
|
580
626
|
"history-version": historyVersionRouter
|
581
627
|
};
|
582
628
|
const historyVersion = {
|
@@ -623,7 +669,7 @@ const historyVersion = {
|
|
623
669
|
}
|
624
670
|
}
|
625
671
|
};
|
626
|
-
const getFeature = () => {
|
672
|
+
const getFeature$1 = () => {
|
627
673
|
if (strapi.ee.features.isEnabled("cms-content-history")) {
|
628
674
|
return {
|
629
675
|
register({ strapi: strapi2 }) {
|
@@ -635,9 +681,9 @@ const getFeature = () => {
|
|
635
681
|
destroy({ strapi: strapi2 }) {
|
636
682
|
getService(strapi2, "lifecycles").destroy();
|
637
683
|
},
|
638
|
-
controllers: controllers$
|
639
|
-
services: services$
|
640
|
-
routes: routes$
|
684
|
+
controllers: controllers$2,
|
685
|
+
services: services$2,
|
686
|
+
routes: routes$2
|
641
687
|
};
|
642
688
|
}
|
643
689
|
return {
|
@@ -646,7 +692,7 @@ const getFeature = () => {
|
|
646
692
|
}
|
647
693
|
};
|
648
694
|
};
|
649
|
-
const history = getFeature();
|
695
|
+
const history = getFeature$1();
|
650
696
|
const register = async ({ strapi: strapi2 }) => {
|
651
697
|
await history.register?.({ strapi: strapi2 });
|
652
698
|
};
|
@@ -654,6 +700,62 @@ const ALLOWED_WEBHOOK_EVENTS = {
|
|
654
700
|
ENTRY_PUBLISH: "entry.publish",
|
655
701
|
ENTRY_UNPUBLISH: "entry.unpublish"
|
656
702
|
};
|
703
|
+
const FEATURE_ID = "preview";
|
704
|
+
const info = { pluginName: "content-manager", type: "admin" };
|
705
|
+
const previewRouter = {
|
706
|
+
type: "admin",
|
707
|
+
routes: [
|
708
|
+
{
|
709
|
+
method: "GET",
|
710
|
+
info,
|
711
|
+
path: "/preview/url/:contentType",
|
712
|
+
handler: "preview.getPreviewURL",
|
713
|
+
config: {
|
714
|
+
policies: ["admin::isAuthenticatedAdmin"]
|
715
|
+
}
|
716
|
+
}
|
717
|
+
]
|
718
|
+
};
|
719
|
+
const routes$1 = {
|
720
|
+
preview: previewRouter
|
721
|
+
};
|
722
|
+
const createPreviewController = () => {
|
723
|
+
return {
|
724
|
+
async getPreviewURL(ctx) {
|
725
|
+
ctx.request;
|
726
|
+
return {
|
727
|
+
data: { url: "" }
|
728
|
+
};
|
729
|
+
}
|
730
|
+
};
|
731
|
+
};
|
732
|
+
const controllers$1 = {
|
733
|
+
preview: createPreviewController
|
734
|
+
/**
|
735
|
+
* Casting is needed because the types aren't aware that Strapi supports
|
736
|
+
* passing a controller factory as the value, instead of a controller object directly
|
737
|
+
*/
|
738
|
+
};
|
739
|
+
const createPreviewService = () => {
|
740
|
+
};
|
741
|
+
const services$1 = {
|
742
|
+
preview: createPreviewService
|
743
|
+
};
|
744
|
+
const getFeature = () => {
|
745
|
+
if (!strapi.features.future.isEnabled(FEATURE_ID)) {
|
746
|
+
return {};
|
747
|
+
}
|
748
|
+
return {
|
749
|
+
bootstrap() {
|
750
|
+
console.log("Bootstrapping preview server");
|
751
|
+
strapi.config.get("admin.preview");
|
752
|
+
},
|
753
|
+
routes: routes$1,
|
754
|
+
controllers: controllers$1,
|
755
|
+
services: services$1
|
756
|
+
};
|
757
|
+
};
|
758
|
+
const preview = getFeature();
|
657
759
|
const bootstrap = async () => {
|
658
760
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
659
761
|
strapi.get("webhookStore").addAllowedEvent(key, value);
|
@@ -663,6 +765,7 @@ const bootstrap = async () => {
|
|
663
765
|
await getService$1("content-types").syncConfigurations();
|
664
766
|
await getService$1("permission").registerPermissions();
|
665
767
|
await history.bootstrap?.({ strapi });
|
768
|
+
await preview.bootstrap?.({ strapi });
|
666
769
|
};
|
667
770
|
const destroy = async ({ strapi: strapi2 }) => {
|
668
771
|
await history.destroy?.({ strapi: strapi2 });
|
@@ -1152,7 +1255,8 @@ const admin = {
|
|
1152
1255
|
};
|
1153
1256
|
const routes = {
|
1154
1257
|
admin,
|
1155
|
-
...history.routes ? history.routes : {}
|
1258
|
+
...history.routes ? history.routes : {},
|
1259
|
+
...preview.routes ? preview.routes : {}
|
1156
1260
|
};
|
1157
1261
|
const hasPermissionsSchema = yup$1.object({
|
1158
1262
|
actions: yup$1.array().of(yup$1.string()),
|
@@ -1163,6 +1267,11 @@ const { createPolicy } = policy;
|
|
1163
1267
|
const hasPermissions = createPolicy({
|
1164
1268
|
name: "plugin::content-manager.hasPermissions",
|
1165
1269
|
validator: validateHasPermissionsInput,
|
1270
|
+
/**
|
1271
|
+
* NOTE: Action aliases are currently not checked at this level (policy).
|
1272
|
+
* This is currently the intended behavior to avoid changing the behavior of API related permissions.
|
1273
|
+
* If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
|
1274
|
+
*/
|
1166
1275
|
handler(ctx, config = {}) {
|
1167
1276
|
const { actions = [], hasAtLeastOne = false } = config;
|
1168
1277
|
const { userAbility } = ctx.state;
|
@@ -1452,7 +1561,7 @@ const { PaginationError, ValidationError } = errors;
|
|
1452
1561
|
const TYPES = ["singleType", "collectionType"];
|
1453
1562
|
const kindSchema = yup$1.string().oneOf(TYPES).nullable();
|
1454
1563
|
const bulkActionInputSchema = yup$1.object({
|
1455
|
-
|
1564
|
+
documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
|
1456
1565
|
}).required();
|
1457
1566
|
const generateUIDInputSchema = yup$1.object({
|
1458
1567
|
contentTypeUID: yup$1.string().required(),
|
@@ -1551,15 +1660,49 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1551
1660
|
}
|
1552
1661
|
}, body);
|
1553
1662
|
};
|
1554
|
-
const
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1663
|
+
const singleLocaleSchema = yup$1.string().nullable();
|
1664
|
+
const multipleLocaleSchema = yup$1.lazy(
|
1665
|
+
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1666
|
+
);
|
1667
|
+
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1668
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1669
|
+
const { allowMultipleLocales } = opts;
|
1670
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1671
|
+
const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1672
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1673
|
+
const schema = yup$1.object().shape({
|
1674
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1675
|
+
status: statusSchema
|
1676
|
+
});
|
1677
|
+
try {
|
1678
|
+
await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1679
|
+
return { locale, status, ...rest };
|
1680
|
+
} catch (error) {
|
1681
|
+
throw new errors.ValidationError(`Validation error: ${error.message}`);
|
1561
1682
|
}
|
1562
|
-
|
1683
|
+
};
|
1684
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1685
|
+
const documentMetadata2 = getService$1("document-metadata");
|
1686
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1687
|
+
let {
|
1688
|
+
meta: { availableLocales, availableStatus }
|
1689
|
+
} = serviceOutput;
|
1690
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1691
|
+
availableLocales = await async.map(
|
1692
|
+
availableLocales,
|
1693
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1694
|
+
);
|
1695
|
+
availableStatus = await async.map(
|
1696
|
+
availableStatus,
|
1697
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1698
|
+
);
|
1699
|
+
return {
|
1700
|
+
...serviceOutput,
|
1701
|
+
meta: {
|
1702
|
+
availableLocales,
|
1703
|
+
availableStatus
|
1704
|
+
}
|
1705
|
+
};
|
1563
1706
|
};
|
1564
1707
|
const createDocument = async (ctx, opts) => {
|
1565
1708
|
const { userAbility, user } = ctx.state;
|
@@ -1574,7 +1717,7 @@ const createDocument = async (ctx, opts) => {
|
|
1574
1717
|
const setCreator = setCreatorFields({ user });
|
1575
1718
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1576
1719
|
const sanitizedBody = await sanitizeFn(body);
|
1577
|
-
const { locale, status
|
1720
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1578
1721
|
return documentManager2.create(model, {
|
1579
1722
|
data: sanitizedBody,
|
1580
1723
|
locale,
|
@@ -1593,7 +1736,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1593
1736
|
}
|
1594
1737
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1595
1738
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1596
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1739
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1597
1740
|
const [documentVersion, documentExists] = await Promise.all([
|
1598
1741
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1599
1742
|
documentManager2.exists(model, id)
|
@@ -1609,7 +1752,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1609
1752
|
throw new errors.ForbiddenError();
|
1610
1753
|
}
|
1611
1754
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1612
|
-
const setCreator = setCreatorFields({ user, isEdition: true });
|
1755
|
+
const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
|
1613
1756
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1614
1757
|
const sanitizedBody = await sanitizeFn(body);
|
1615
1758
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1631,7 +1774,7 @@ const collectionTypes = {
|
|
1631
1774
|
}
|
1632
1775
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1633
1776
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1634
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
1777
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1635
1778
|
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1636
1779
|
{ ...permissionQuery, populate, locale, status },
|
1637
1780
|
model
|
@@ -1660,14 +1803,13 @@ const collectionTypes = {
|
|
1660
1803
|
const { userAbility } = ctx.state;
|
1661
1804
|
const { model, id } = ctx.params;
|
1662
1805
|
const documentManager2 = getService$1("document-manager");
|
1663
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1664
1806
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1665
1807
|
if (permissionChecker2.cannot.read()) {
|
1666
1808
|
return ctx.forbidden();
|
1667
1809
|
}
|
1668
1810
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1669
1811
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1670
|
-
const { locale, status
|
1812
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1671
1813
|
const version = await documentManager2.findOne(id, model, {
|
1672
1814
|
populate,
|
1673
1815
|
locale,
|
@@ -1678,9 +1820,11 @@ const collectionTypes = {
|
|
1678
1820
|
if (!exists) {
|
1679
1821
|
return ctx.notFound();
|
1680
1822
|
}
|
1681
|
-
const { meta } = await
|
1823
|
+
const { meta } = await formatDocumentWithMetadata(
|
1824
|
+
permissionChecker2,
|
1682
1825
|
model,
|
1683
|
-
|
1826
|
+
// @ts-expect-error TODO: fix
|
1827
|
+
{ documentId: id, locale, publishedAt: null },
|
1684
1828
|
{ availableLocales: true, availableStatus: false }
|
1685
1829
|
);
|
1686
1830
|
ctx.body = { data: {}, meta };
|
@@ -1690,12 +1834,11 @@ const collectionTypes = {
|
|
1690
1834
|
return ctx.forbidden();
|
1691
1835
|
}
|
1692
1836
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1693
|
-
ctx.body = await
|
1837
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1694
1838
|
},
|
1695
1839
|
async create(ctx) {
|
1696
1840
|
const { userAbility } = ctx.state;
|
1697
1841
|
const { model } = ctx.params;
|
1698
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1699
1842
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1700
1843
|
const [totalEntries, document] = await Promise.all([
|
1701
1844
|
strapi.db.query(model).count(),
|
@@ -1703,7 +1846,7 @@ const collectionTypes = {
|
|
1703
1846
|
]);
|
1704
1847
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1705
1848
|
ctx.status = 201;
|
1706
|
-
ctx.body = await
|
1849
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1707
1850
|
// Empty metadata as it's not relevant for a new document
|
1708
1851
|
availableLocales: false,
|
1709
1852
|
availableStatus: false
|
@@ -1717,25 +1860,23 @@ const collectionTypes = {
|
|
1717
1860
|
async update(ctx) {
|
1718
1861
|
const { userAbility } = ctx.state;
|
1719
1862
|
const { model } = ctx.params;
|
1720
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1721
1863
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1722
1864
|
const updatedVersion = await updateDocument(ctx);
|
1723
1865
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1724
|
-
ctx.body = await
|
1866
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1725
1867
|
},
|
1726
1868
|
async clone(ctx) {
|
1727
1869
|
const { userAbility, user } = ctx.state;
|
1728
1870
|
const { model, sourceId: id } = ctx.params;
|
1729
1871
|
const { body } = ctx.request;
|
1730
1872
|
const documentManager2 = getService$1("document-manager");
|
1731
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1732
1873
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1733
1874
|
if (permissionChecker2.cannot.create()) {
|
1734
1875
|
return ctx.forbidden();
|
1735
1876
|
}
|
1736
1877
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1737
1878
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1738
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1879
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1739
1880
|
const document = await documentManager2.findOne(id, model, {
|
1740
1881
|
populate,
|
1741
1882
|
locale,
|
@@ -1751,7 +1892,7 @@ const collectionTypes = {
|
|
1751
1892
|
const sanitizedBody = await sanitizeFn(body);
|
1752
1893
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1753
1894
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1754
|
-
ctx.body = await
|
1895
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1755
1896
|
// Empty metadata as it's not relevant for a new document
|
1756
1897
|
availableLocales: false,
|
1757
1898
|
availableStatus: false
|
@@ -1780,7 +1921,7 @@ const collectionTypes = {
|
|
1780
1921
|
}
|
1781
1922
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1782
1923
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1783
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
1924
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1784
1925
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1785
1926
|
if (documentLocales.length === 0) {
|
1786
1927
|
return ctx.notFound();
|
@@ -1802,7 +1943,6 @@ const collectionTypes = {
|
|
1802
1943
|
const { id, model } = ctx.params;
|
1803
1944
|
const { body } = ctx.request;
|
1804
1945
|
const documentManager2 = getService$1("document-manager");
|
1805
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1806
1946
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1807
1947
|
if (permissionChecker2.cannot.publish()) {
|
1808
1948
|
return ctx.forbidden();
|
@@ -1810,25 +1950,52 @@ const collectionTypes = {
|
|
1810
1950
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1811
1951
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1812
1952
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1813
|
-
|
1953
|
+
let document;
|
1954
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1955
|
+
const isCreate = isNil$1(id);
|
1956
|
+
if (isCreate) {
|
1957
|
+
if (permissionChecker2.cannot.create()) {
|
1958
|
+
throw new errors.ForbiddenError();
|
1959
|
+
}
|
1960
|
+
document = await createDocument(ctx, { populate });
|
1961
|
+
}
|
1962
|
+
const isUpdate = !isCreate;
|
1963
|
+
if (isUpdate) {
|
1964
|
+
const documentExists = documentManager2.exists(model, id);
|
1965
|
+
if (!documentExists) {
|
1966
|
+
throw new errors.NotFoundError("Document not found");
|
1967
|
+
}
|
1968
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
1969
|
+
if (!document) {
|
1970
|
+
if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
|
1971
|
+
throw new errors.ForbiddenError();
|
1972
|
+
}
|
1973
|
+
document = await updateDocument(ctx);
|
1974
|
+
} else if (permissionChecker2.can.update(document)) {
|
1975
|
+
await updateDocument(ctx);
|
1976
|
+
}
|
1977
|
+
}
|
1814
1978
|
if (permissionChecker2.cannot.publish(document)) {
|
1815
1979
|
throw new errors.ForbiddenError();
|
1816
1980
|
}
|
1817
|
-
const
|
1818
|
-
return documentManager2.publish(document.documentId, model, {
|
1981
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1819
1982
|
locale
|
1820
1983
|
// TODO: Allow setting creator fields on publish
|
1821
1984
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1822
1985
|
});
|
1986
|
+
if (!publishResult || publishResult.length === 0) {
|
1987
|
+
throw new errors.NotFoundError("Document not found or already published.");
|
1988
|
+
}
|
1989
|
+
return publishResult[0];
|
1823
1990
|
});
|
1824
1991
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1825
|
-
ctx.body = await
|
1992
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1826
1993
|
},
|
1827
1994
|
async bulkPublish(ctx) {
|
1828
1995
|
const { userAbility } = ctx.state;
|
1829
1996
|
const { model } = ctx.params;
|
1830
1997
|
const { body } = ctx.request;
|
1831
|
-
const {
|
1998
|
+
const { documentIds } = body;
|
1832
1999
|
await validateBulkActionInput(body);
|
1833
2000
|
const documentManager2 = getService$1("document-manager");
|
1834
2001
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1837,8 +2004,13 @@ const collectionTypes = {
|
|
1837
2004
|
}
|
1838
2005
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1839
2006
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1840
|
-
const
|
1841
|
-
|
2007
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2008
|
+
allowMultipleLocales: true
|
2009
|
+
});
|
2010
|
+
const entityPromises = documentIds.map(
|
2011
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
2012
|
+
);
|
2013
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1842
2014
|
for (const entity of entities) {
|
1843
2015
|
if (!entity) {
|
1844
2016
|
return ctx.notFound();
|
@@ -1847,24 +2019,27 @@ const collectionTypes = {
|
|
1847
2019
|
return ctx.forbidden();
|
1848
2020
|
}
|
1849
2021
|
}
|
1850
|
-
const
|
2022
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1851
2023
|
ctx.body = { count };
|
1852
2024
|
},
|
1853
2025
|
async bulkUnpublish(ctx) {
|
1854
2026
|
const { userAbility } = ctx.state;
|
1855
2027
|
const { model } = ctx.params;
|
1856
2028
|
const { body } = ctx.request;
|
1857
|
-
const {
|
2029
|
+
const { documentIds } = body;
|
1858
2030
|
await validateBulkActionInput(body);
|
1859
2031
|
const documentManager2 = getService$1("document-manager");
|
1860
2032
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1861
2033
|
if (permissionChecker2.cannot.unpublish()) {
|
1862
2034
|
return ctx.forbidden();
|
1863
2035
|
}
|
1864
|
-
const
|
1865
|
-
|
1866
|
-
|
1867
|
-
const
|
2036
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
2037
|
+
allowMultipleLocales: true
|
2038
|
+
});
|
2039
|
+
const entityPromises = documentIds.map(
|
2040
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
2041
|
+
);
|
2042
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1868
2043
|
for (const entity of entities) {
|
1869
2044
|
if (!entity) {
|
1870
2045
|
return ctx.notFound();
|
@@ -1873,7 +2048,8 @@ const collectionTypes = {
|
|
1873
2048
|
return ctx.forbidden();
|
1874
2049
|
}
|
1875
2050
|
}
|
1876
|
-
const
|
2051
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
2052
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1877
2053
|
ctx.body = { count };
|
1878
2054
|
},
|
1879
2055
|
async unpublish(ctx) {
|
@@ -1883,7 +2059,6 @@ const collectionTypes = {
|
|
1883
2059
|
body: { discardDraft, ...body }
|
1884
2060
|
} = ctx.request;
|
1885
2061
|
const documentManager2 = getService$1("document-manager");
|
1886
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1887
2062
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1888
2063
|
if (permissionChecker2.cannot.unpublish()) {
|
1889
2064
|
return ctx.forbidden();
|
@@ -1893,7 +2068,7 @@ const collectionTypes = {
|
|
1893
2068
|
}
|
1894
2069
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1895
2070
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1896
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2071
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1897
2072
|
const document = await documentManager2.findOne(id, model, {
|
1898
2073
|
populate,
|
1899
2074
|
locale,
|
@@ -1915,7 +2090,7 @@ const collectionTypes = {
|
|
1915
2090
|
ctx.body = await async.pipe(
|
1916
2091
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1917
2092
|
permissionChecker2.sanitizeOutput,
|
1918
|
-
(document2) =>
|
2093
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1919
2094
|
)(document);
|
1920
2095
|
});
|
1921
2096
|
},
|
@@ -1924,14 +2099,13 @@ const collectionTypes = {
|
|
1924
2099
|
const { id, model } = ctx.params;
|
1925
2100
|
const { body } = ctx.request;
|
1926
2101
|
const documentManager2 = getService$1("document-manager");
|
1927
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1928
2102
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1929
2103
|
if (permissionChecker2.cannot.discard()) {
|
1930
2104
|
return ctx.forbidden();
|
1931
2105
|
}
|
1932
2106
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1933
2107
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1934
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2108
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1935
2109
|
const document = await documentManager2.findOne(id, model, {
|
1936
2110
|
populate,
|
1937
2111
|
locale,
|
@@ -1946,14 +2120,14 @@ const collectionTypes = {
|
|
1946
2120
|
ctx.body = await async.pipe(
|
1947
2121
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1948
2122
|
permissionChecker2.sanitizeOutput,
|
1949
|
-
(document2) =>
|
2123
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1950
2124
|
)(document);
|
1951
2125
|
},
|
1952
2126
|
async bulkDelete(ctx) {
|
1953
2127
|
const { userAbility } = ctx.state;
|
1954
2128
|
const { model } = ctx.params;
|
1955
2129
|
const { query, body } = ctx.request;
|
1956
|
-
const {
|
2130
|
+
const { documentIds } = body;
|
1957
2131
|
await validateBulkActionInput(body);
|
1958
2132
|
const documentManager2 = getService$1("document-manager");
|
1959
2133
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1961,14 +2135,22 @@ const collectionTypes = {
|
|
1961
2135
|
return ctx.forbidden();
|
1962
2136
|
}
|
1963
2137
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1964
|
-
const
|
1965
|
-
const
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
2138
|
+
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2139
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2140
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2141
|
+
populate,
|
2142
|
+
locale
|
2143
|
+
});
|
2144
|
+
if (documentLocales.length === 0) {
|
2145
|
+
return ctx.notFound();
|
2146
|
+
}
|
2147
|
+
for (const document of documentLocales) {
|
2148
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2149
|
+
return ctx.forbidden();
|
1969
2150
|
}
|
1970
|
-
}
|
1971
|
-
const
|
2151
|
+
}
|
2152
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2153
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1972
2154
|
ctx.body = { count };
|
1973
2155
|
},
|
1974
2156
|
async countDraftRelations(ctx) {
|
@@ -1981,7 +2163,7 @@ const collectionTypes = {
|
|
1981
2163
|
}
|
1982
2164
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1983
2165
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1984
|
-
const { locale, status
|
2166
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1985
2167
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
1986
2168
|
if (!entity) {
|
1987
2169
|
return ctx.notFound();
|
@@ -1996,7 +2178,7 @@ const collectionTypes = {
|
|
1996
2178
|
},
|
1997
2179
|
async countManyEntriesDraftRelations(ctx) {
|
1998
2180
|
const { userAbility } = ctx.state;
|
1999
|
-
const ids = ctx.request.query.
|
2181
|
+
const ids = ctx.request.query.documentIds;
|
2000
2182
|
const locale = ctx.request.query.locale;
|
2001
2183
|
const { model } = ctx.params;
|
2002
2184
|
const documentManager2 = getService$1("document-manager");
|
@@ -2004,16 +2186,16 @@ const collectionTypes = {
|
|
2004
2186
|
if (permissionChecker2.cannot.read()) {
|
2005
2187
|
return ctx.forbidden();
|
2006
2188
|
}
|
2007
|
-
const
|
2189
|
+
const documents = await documentManager2.findMany(
|
2008
2190
|
{
|
2009
2191
|
filters: {
|
2010
|
-
|
2192
|
+
documentId: ids
|
2011
2193
|
},
|
2012
2194
|
locale
|
2013
2195
|
},
|
2014
2196
|
model
|
2015
2197
|
);
|
2016
|
-
if (!
|
2198
|
+
if (!documents) {
|
2017
2199
|
return ctx.notFound();
|
2018
2200
|
}
|
2019
2201
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2204,32 +2386,37 @@ const sanitizeMainField = (model, mainField, userAbility) => {
|
|
2204
2386
|
userAbility,
|
2205
2387
|
model: model.uid
|
2206
2388
|
});
|
2207
|
-
|
2389
|
+
const isMainFieldListable = isListable(model, mainField);
|
2390
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2391
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2208
2392
|
return "id";
|
2209
2393
|
}
|
2210
|
-
if (
|
2211
|
-
|
2212
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2213
|
-
userAbility,
|
2214
|
-
model: "plugin::users-permissions.user"
|
2215
|
-
});
|
2216
|
-
if (userPermissionChecker.can.read()) {
|
2217
|
-
return "name";
|
2218
|
-
}
|
2219
|
-
}
|
2220
|
-
return "id";
|
2394
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2395
|
+
return "name";
|
2221
2396
|
}
|
2222
2397
|
return mainField;
|
2223
2398
|
};
|
2224
|
-
const addStatusToRelations = async (
|
2225
|
-
if (!contentTypes$1.hasDraftAndPublish(strapi.
|
2399
|
+
const addStatusToRelations = async (targetUid, relations2) => {
|
2400
|
+
if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
2226
2401
|
return relations2;
|
2227
2402
|
}
|
2228
2403
|
const documentMetadata2 = getService$1("document-metadata");
|
2229
|
-
|
2404
|
+
if (!relations2.length) {
|
2405
|
+
return relations2;
|
2406
|
+
}
|
2407
|
+
const firstRelation = relations2[0];
|
2408
|
+
const filters = {
|
2409
|
+
documentId: { $in: relations2.map((r) => r.documentId) },
|
2410
|
+
// NOTE: find the "opposite" status
|
2411
|
+
publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
|
2412
|
+
};
|
2413
|
+
const availableStatus = await strapi.query(targetUid).findMany({
|
2414
|
+
select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
|
2415
|
+
filters
|
2416
|
+
});
|
2230
2417
|
return relations2.map((relation) => {
|
2231
|
-
const availableStatuses =
|
2232
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2418
|
+
const availableStatuses = availableStatus.filter(
|
2419
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2233
2420
|
);
|
2234
2421
|
return {
|
2235
2422
|
...relation,
|
@@ -2250,11 +2437,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2250
2437
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2251
2438
|
const isSourceLocalized = isLocalized(sourceModel);
|
2252
2439
|
const isTargetLocalized = isLocalized(targetModel);
|
2253
|
-
let validatedLocale = locale;
|
2254
|
-
if (!targetModel || !isTargetLocalized)
|
2255
|
-
validatedLocale = void 0;
|
2256
2440
|
return {
|
2257
|
-
locale
|
2441
|
+
locale,
|
2258
2442
|
isSourceLocalized,
|
2259
2443
|
isTargetLocalized
|
2260
2444
|
};
|
@@ -2357,7 +2541,7 @@ const relations = {
|
|
2357
2541
|
attribute,
|
2358
2542
|
fieldsToSelect,
|
2359
2543
|
mainField,
|
2360
|
-
source: { schema: sourceSchema },
|
2544
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2361
2545
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2362
2546
|
sourceSchema,
|
2363
2547
|
targetSchema,
|
@@ -2379,7 +2563,8 @@ const relations = {
|
|
2379
2563
|
fieldsToSelect,
|
2380
2564
|
mainField,
|
2381
2565
|
source: {
|
2382
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2566
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2567
|
+
isLocalized: isSourceLocalized
|
2383
2568
|
},
|
2384
2569
|
target: {
|
2385
2570
|
schema: { uid: targetUid },
|
@@ -2417,12 +2602,16 @@ const relations = {
|
|
2417
2602
|
} else {
|
2418
2603
|
where.id = id;
|
2419
2604
|
}
|
2420
|
-
|
2421
|
-
|
2605
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2606
|
+
if (!isEmpty(publishedAt)) {
|
2607
|
+
where[`${alias}.published_at`] = publishedAt;
|
2422
2608
|
}
|
2423
|
-
if (
|
2609
|
+
if (isTargetLocalized && locale) {
|
2424
2610
|
where[`${alias}.locale`] = locale;
|
2425
2611
|
}
|
2612
|
+
if (isSourceLocalized && locale) {
|
2613
|
+
where.locale = locale;
|
2614
|
+
}
|
2426
2615
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2427
2616
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2428
2617
|
}
|
@@ -2440,7 +2629,8 @@ const relations = {
|
|
2440
2629
|
id: { $notIn: uniq(idsToOmit) }
|
2441
2630
|
});
|
2442
2631
|
}
|
2443
|
-
const
|
2632
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2633
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2444
2634
|
ctx.body = {
|
2445
2635
|
...res,
|
2446
2636
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2455,29 +2645,39 @@ const relations = {
|
|
2455
2645
|
attribute,
|
2456
2646
|
targetField,
|
2457
2647
|
fieldsToSelect,
|
2458
|
-
|
2459
|
-
|
2460
|
-
}
|
2461
|
-
target: {
|
2462
|
-
schema: { uid: targetUid }
|
2463
|
-
}
|
2648
|
+
status,
|
2649
|
+
source: { schema: sourceSchema },
|
2650
|
+
target: { schema: targetSchema }
|
2464
2651
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2652
|
+
const { uid: sourceUid } = sourceSchema;
|
2653
|
+
const { uid: targetUid } = targetSchema;
|
2465
2654
|
const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
|
2466
2655
|
const dbQuery = strapi.db.query(sourceUid);
|
2467
2656
|
const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
|
2657
|
+
const filters = {};
|
2658
|
+
if (sourceSchema?.options?.draftAndPublish) {
|
2659
|
+
if (targetSchema?.options?.draftAndPublish) {
|
2660
|
+
if (status === "published") {
|
2661
|
+
filters.publishedAt = { $notNull: true };
|
2662
|
+
} else {
|
2663
|
+
filters.publishedAt = { $null: true };
|
2664
|
+
}
|
2665
|
+
}
|
2666
|
+
} else if (targetSchema?.options?.draftAndPublish) {
|
2667
|
+
filters.publishedAt = { $null: true };
|
2668
|
+
}
|
2468
2669
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2469
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2670
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2470
2671
|
ordering: "desc",
|
2471
2672
|
page: ctx.request.query.page,
|
2472
|
-
pageSize: ctx.request.query.pageSize
|
2673
|
+
pageSize: ctx.request.query.pageSize,
|
2674
|
+
filters
|
2473
2675
|
});
|
2474
2676
|
const loadedIds = res.results.map((item) => item.id);
|
2475
2677
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2476
2678
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2477
2679
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2478
|
-
ordering: "desc"
|
2479
|
-
page: ctx.request.query.page,
|
2480
|
-
pageSize: ctx.request.query.pageSize
|
2680
|
+
ordering: "desc"
|
2481
2681
|
});
|
2482
2682
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2483
2683
|
ctx.body = {
|
@@ -2509,7 +2709,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2509
2709
|
throw new errors.ForbiddenError();
|
2510
2710
|
}
|
2511
2711
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2512
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2712
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2513
2713
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2514
2714
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2515
2715
|
// Find the first document to check if it exists
|
@@ -2546,12 +2746,11 @@ const singleTypes = {
|
|
2546
2746
|
const { model } = ctx.params;
|
2547
2747
|
const { query = {} } = ctx.request;
|
2548
2748
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2549
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2550
2749
|
if (permissionChecker2.cannot.read()) {
|
2551
2750
|
return ctx.forbidden();
|
2552
2751
|
}
|
2553
2752
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2554
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2753
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2555
2754
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2556
2755
|
if (!version) {
|
2557
2756
|
if (permissionChecker2.cannot.create()) {
|
@@ -2561,9 +2760,11 @@ const singleTypes = {
|
|
2561
2760
|
if (!document) {
|
2562
2761
|
return ctx.notFound();
|
2563
2762
|
}
|
2564
|
-
const { meta } = await
|
2763
|
+
const { meta } = await formatDocumentWithMetadata(
|
2764
|
+
permissionChecker2,
|
2565
2765
|
model,
|
2566
|
-
|
2766
|
+
// @ts-expect-error - fix types
|
2767
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2567
2768
|
{ availableLocales: true, availableStatus: false }
|
2568
2769
|
);
|
2569
2770
|
ctx.body = { data: {}, meta };
|
@@ -2573,16 +2774,15 @@ const singleTypes = {
|
|
2573
2774
|
return ctx.forbidden();
|
2574
2775
|
}
|
2575
2776
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2576
|
-
ctx.body = await
|
2777
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2577
2778
|
},
|
2578
2779
|
async createOrUpdate(ctx) {
|
2579
2780
|
const { userAbility } = ctx.state;
|
2580
2781
|
const { model } = ctx.params;
|
2581
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2582
2782
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2583
2783
|
const document = await createOrUpdateDocument(ctx);
|
2584
2784
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2585
|
-
ctx.body = await
|
2785
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2586
2786
|
},
|
2587
2787
|
async delete(ctx) {
|
2588
2788
|
const { userAbility } = ctx.state;
|
@@ -2595,7 +2795,7 @@ const singleTypes = {
|
|
2595
2795
|
}
|
2596
2796
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2597
2797
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2598
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2798
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2599
2799
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2600
2800
|
populate,
|
2601
2801
|
locale
|
@@ -2618,7 +2818,6 @@ const singleTypes = {
|
|
2618
2818
|
const { model } = ctx.params;
|
2619
2819
|
const { query = {} } = ctx.request;
|
2620
2820
|
const documentManager2 = getService$1("document-manager");
|
2621
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2622
2821
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2623
2822
|
if (permissionChecker2.cannot.publish()) {
|
2624
2823
|
return ctx.forbidden();
|
@@ -2633,11 +2832,12 @@ const singleTypes = {
|
|
2633
2832
|
if (permissionChecker2.cannot.publish(document)) {
|
2634
2833
|
throw new errors.ForbiddenError();
|
2635
2834
|
}
|
2636
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2637
|
-
|
2835
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2836
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2837
|
+
return publishResult.at(0);
|
2638
2838
|
});
|
2639
2839
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2640
|
-
ctx.body = await
|
2840
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2641
2841
|
},
|
2642
2842
|
async unpublish(ctx) {
|
2643
2843
|
const { userAbility } = ctx.state;
|
@@ -2647,7 +2847,6 @@ const singleTypes = {
|
|
2647
2847
|
query = {}
|
2648
2848
|
} = ctx.request;
|
2649
2849
|
const documentManager2 = getService$1("document-manager");
|
2650
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2651
2850
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2652
2851
|
if (permissionChecker2.cannot.unpublish()) {
|
2653
2852
|
return ctx.forbidden();
|
@@ -2656,7 +2855,7 @@ const singleTypes = {
|
|
2656
2855
|
return ctx.forbidden();
|
2657
2856
|
}
|
2658
2857
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2659
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2858
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2660
2859
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2661
2860
|
if (!document) {
|
2662
2861
|
return ctx.notFound();
|
@@ -2674,7 +2873,7 @@ const singleTypes = {
|
|
2674
2873
|
ctx.body = await async.pipe(
|
2675
2874
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2676
2875
|
permissionChecker2.sanitizeOutput,
|
2677
|
-
(document2) =>
|
2876
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2678
2877
|
)(document);
|
2679
2878
|
});
|
2680
2879
|
},
|
@@ -2683,13 +2882,12 @@ const singleTypes = {
|
|
2683
2882
|
const { model } = ctx.params;
|
2684
2883
|
const { body, query = {} } = ctx.request;
|
2685
2884
|
const documentManager2 = getService$1("document-manager");
|
2686
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2687
2885
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2688
2886
|
if (permissionChecker2.cannot.discard()) {
|
2689
2887
|
return ctx.forbidden();
|
2690
2888
|
}
|
2691
2889
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2692
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2890
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2693
2891
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2694
2892
|
if (!document) {
|
2695
2893
|
return ctx.notFound();
|
@@ -2700,7 +2898,7 @@ const singleTypes = {
|
|
2700
2898
|
ctx.body = await async.pipe(
|
2701
2899
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2702
2900
|
permissionChecker2.sanitizeOutput,
|
2703
|
-
(document2) =>
|
2901
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2704
2902
|
)(document);
|
2705
2903
|
},
|
2706
2904
|
async countDraftRelations(ctx) {
|
@@ -2709,7 +2907,7 @@ const singleTypes = {
|
|
2709
2907
|
const { query } = ctx.request;
|
2710
2908
|
const documentManager2 = getService$1("document-manager");
|
2711
2909
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2712
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2910
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2713
2911
|
if (permissionChecker2.cannot.read()) {
|
2714
2912
|
return ctx.forbidden();
|
2715
2913
|
}
|
@@ -2730,7 +2928,7 @@ const uid$1 = {
|
|
2730
2928
|
async generateUID(ctx) {
|
2731
2929
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2732
2930
|
const { query = {} } = ctx.request;
|
2733
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2931
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2734
2932
|
await validateUIDField(contentTypeUID, field);
|
2735
2933
|
const uidService = getService$1("uid");
|
2736
2934
|
ctx.body = {
|
@@ -2742,7 +2940,7 @@ const uid$1 = {
|
|
2742
2940
|
ctx.request.body
|
2743
2941
|
);
|
2744
2942
|
const { query = {} } = ctx.request;
|
2745
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2943
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2746
2944
|
await validateUIDField(contentTypeUID, field);
|
2747
2945
|
const uidService = getService$1("uid");
|
2748
2946
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -2765,7 +2963,8 @@ const controllers = {
|
|
2765
2963
|
relations,
|
2766
2964
|
"single-types": singleTypes,
|
2767
2965
|
uid: uid$1,
|
2768
|
-
...history.controllers ? history.controllers : {}
|
2966
|
+
...history.controllers ? history.controllers : {},
|
2967
|
+
...preview.controllers ? preview.controllers : {}
|
2769
2968
|
};
|
2770
2969
|
const keys = {
|
2771
2970
|
CONFIGURATION: "configuration"
|
@@ -3385,12 +3584,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3385
3584
|
ability: userAbility,
|
3386
3585
|
model
|
3387
3586
|
});
|
3388
|
-
const
|
3587
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3588
|
+
const toSubject = (entity) => {
|
3589
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3590
|
+
};
|
3389
3591
|
const can = (action, entity, field) => {
|
3390
|
-
|
3592
|
+
const subject = toSubject(entity);
|
3593
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3594
|
+
return (
|
3595
|
+
// Test the original action to see if it passes
|
3596
|
+
userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
|
3597
|
+
aliases.some((alias) => userAbility.can(alias, subject, field))
|
3598
|
+
);
|
3391
3599
|
};
|
3392
3600
|
const cannot = (action, entity, field) => {
|
3393
|
-
|
3601
|
+
const subject = toSubject(entity);
|
3602
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3603
|
+
return (
|
3604
|
+
// Test both the original action
|
3605
|
+
userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
|
3606
|
+
aliases.every((alias) => userAbility.cannot(alias, subject, field))
|
3607
|
+
);
|
3394
3608
|
};
|
3395
3609
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3396
3610
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3533,7 +3747,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3533
3747
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3534
3748
|
}
|
3535
3749
|
});
|
3536
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
|
3750
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
|
3537
3751
|
const { isAnyToMany } = strapiUtils.relations;
|
3538
3752
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
|
3539
3753
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3624,6 +3838,42 @@ const getDeepPopulate = (uid2, {
|
|
3624
3838
|
{}
|
3625
3839
|
);
|
3626
3840
|
};
|
3841
|
+
const getValidatableFieldsPopulate = (uid2, {
|
3842
|
+
initialPopulate = {},
|
3843
|
+
countMany = false,
|
3844
|
+
countOne = false,
|
3845
|
+
maxLevel = Infinity
|
3846
|
+
} = {}, level = 1) => {
|
3847
|
+
if (level > maxLevel) {
|
3848
|
+
return {};
|
3849
|
+
}
|
3850
|
+
const model = strapi.getModel(uid2);
|
3851
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3852
|
+
if (!getDoesAttributeRequireValidation(attribute)) {
|
3853
|
+
return populateAcc;
|
3854
|
+
}
|
3855
|
+
if (isScalarAttribute(attribute)) {
|
3856
|
+
return merge(populateAcc, {
|
3857
|
+
[attributeName]: true
|
3858
|
+
});
|
3859
|
+
}
|
3860
|
+
return merge(
|
3861
|
+
populateAcc,
|
3862
|
+
getPopulateFor(
|
3863
|
+
attributeName,
|
3864
|
+
model,
|
3865
|
+
{
|
3866
|
+
// @ts-expect-error - improve types
|
3867
|
+
initialPopulate: initialPopulate?.[attributeName],
|
3868
|
+
countMany,
|
3869
|
+
countOne,
|
3870
|
+
maxLevel
|
3871
|
+
},
|
3872
|
+
level
|
3873
|
+
)
|
3874
|
+
);
|
3875
|
+
}, {});
|
3876
|
+
};
|
3627
3877
|
const getDeepPopulateDraftCount = (uid2) => {
|
3628
3878
|
const model = strapi.getModel(uid2);
|
3629
3879
|
let hasRelations = false;
|
@@ -3631,6 +3881,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3631
3881
|
const attribute = model.attributes[attributeName];
|
3632
3882
|
switch (attribute.type) {
|
3633
3883
|
case "relation": {
|
3884
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
3885
|
+
if (isMorphRelation) {
|
3886
|
+
break;
|
3887
|
+
}
|
3634
3888
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3635
3889
|
populateAcc[attributeName] = {
|
3636
3890
|
count: true,
|
@@ -3645,22 +3899,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3645
3899
|
attribute.component
|
3646
3900
|
);
|
3647
3901
|
if (childHasRelations) {
|
3648
|
-
populateAcc[attributeName] = {
|
3902
|
+
populateAcc[attributeName] = {
|
3903
|
+
populate: populate2
|
3904
|
+
};
|
3649
3905
|
hasRelations = true;
|
3650
3906
|
}
|
3651
3907
|
break;
|
3652
3908
|
}
|
3653
3909
|
case "dynamiczone": {
|
3654
|
-
const
|
3655
|
-
const { populate:
|
3656
|
-
if (
|
3910
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
3911
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
3912
|
+
if (componentHasRelations) {
|
3657
3913
|
hasRelations = true;
|
3658
|
-
return
|
3914
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3659
3915
|
}
|
3660
3916
|
return acc;
|
3661
3917
|
}, {});
|
3662
|
-
if (!isEmpty(
|
3663
|
-
populateAcc[attributeName] = {
|
3918
|
+
if (!isEmpty(dzPopulateFragment)) {
|
3919
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3664
3920
|
}
|
3665
3921
|
break;
|
3666
3922
|
}
|
@@ -3852,41 +4108,72 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3852
4108
|
"updatedBy",
|
3853
4109
|
"status"
|
3854
4110
|
];
|
3855
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
4111
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
4112
|
+
"id",
|
4113
|
+
"locale",
|
4114
|
+
"updatedAt",
|
4115
|
+
"createdAt",
|
4116
|
+
"status",
|
4117
|
+
"publishedAt",
|
4118
|
+
"documentId"
|
4119
|
+
];
|
3856
4120
|
const CONTENT_MANAGER_STATUS = {
|
3857
4121
|
PUBLISHED: "published",
|
3858
4122
|
DRAFT: "draft",
|
3859
4123
|
MODIFIED: "modified"
|
3860
4124
|
};
|
3861
|
-
const
|
3862
|
-
if (!
|
4125
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
4126
|
+
if (!version || !version.updatedAt) {
|
3863
4127
|
return false;
|
3864
4128
|
}
|
3865
|
-
const
|
3866
|
-
const
|
3867
|
-
|
3868
|
-
return difference2 <= threshold;
|
4129
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
4130
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
4131
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3869
4132
|
};
|
3870
4133
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3871
4134
|
/**
|
3872
4135
|
* Returns available locales of a document for the current status
|
3873
4136
|
*/
|
3874
|
-
getAvailableLocales(uid2, version, allVersions) {
|
4137
|
+
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3875
4138
|
const versionsByLocale = groupBy("locale", allVersions);
|
3876
|
-
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
4139
|
+
if (version.locale) {
|
4140
|
+
delete versionsByLocale[version.locale];
|
4141
|
+
}
|
4142
|
+
const model = strapi2.getModel(uid2);
|
4143
|
+
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
4144
|
+
const traversalFunction = async (localeVersion) => traverseEntity(
|
4145
|
+
({ key }, { remove }) => {
|
4146
|
+
if (keysToKeep.includes(key)) {
|
4147
|
+
return;
|
4148
|
+
}
|
4149
|
+
remove(key);
|
4150
|
+
},
|
4151
|
+
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
4152
|
+
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
4153
|
+
localeVersion
|
4154
|
+
);
|
4155
|
+
const mappingResult = await async.map(
|
4156
|
+
Object.values(versionsByLocale),
|
4157
|
+
async (localeVersions) => {
|
4158
|
+
const mappedLocaleVersions = await async.map(
|
4159
|
+
localeVersions,
|
4160
|
+
traversalFunction
|
4161
|
+
);
|
4162
|
+
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
4163
|
+
return mappedLocaleVersions[0];
|
4164
|
+
}
|
4165
|
+
const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
|
4166
|
+
const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
|
4167
|
+
if (!draftVersion) {
|
4168
|
+
return;
|
4169
|
+
}
|
4170
|
+
return {
|
4171
|
+
...draftVersion,
|
4172
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4173
|
+
};
|
3880
4174
|
}
|
3881
|
-
|
3882
|
-
|
3883
|
-
if (!draftVersion)
|
3884
|
-
return;
|
3885
|
-
return {
|
3886
|
-
...pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
|
3887
|
-
status: this.getStatus(draftVersion, otherVersions)
|
3888
|
-
};
|
3889
|
-
}).filter(Boolean);
|
4175
|
+
);
|
4176
|
+
return mappingResult.filter(Boolean);
|
3890
4177
|
},
|
3891
4178
|
/**
|
3892
4179
|
* Returns available status of a document for the current locale
|
@@ -3924,26 +4211,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3924
4211
|
});
|
3925
4212
|
},
|
3926
4213
|
getStatus(version, otherDocumentStatuses) {
|
3927
|
-
|
3928
|
-
|
3929
|
-
|
4214
|
+
let draftVersion;
|
4215
|
+
let publishedVersion;
|
4216
|
+
if (version.publishedAt) {
|
4217
|
+
publishedVersion = version;
|
4218
|
+
} else {
|
4219
|
+
draftVersion = version;
|
3930
4220
|
}
|
3931
|
-
|
3932
|
-
|
3933
|
-
|
3934
|
-
|
3935
|
-
|
4221
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4222
|
+
if (otherVersion?.publishedAt) {
|
4223
|
+
publishedVersion = otherVersion;
|
4224
|
+
} else if (otherVersion) {
|
4225
|
+
draftVersion = otherVersion;
|
3936
4226
|
}
|
3937
|
-
if (
|
4227
|
+
if (!draftVersion)
|
3938
4228
|
return CONTENT_MANAGER_STATUS.PUBLISHED;
|
3939
|
-
|
3940
|
-
|
4229
|
+
if (!publishedVersion)
|
4230
|
+
return CONTENT_MANAGER_STATUS.DRAFT;
|
4231
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4232
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3941
4233
|
},
|
4234
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4235
|
+
// We could refactor this so the locales are only loaded when they're
|
4236
|
+
// needed. e.g. in the bulk locale action modal.
|
3942
4237
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4238
|
+
const populate = getValidatableFieldsPopulate(uid2);
|
3943
4239
|
const versions = await strapi2.db.query(uid2).findMany({
|
3944
4240
|
where: { documentId: version.documentId },
|
3945
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
3946
4241
|
populate: {
|
4242
|
+
// Populate only fields that require validation for bulk locale actions
|
4243
|
+
...populate,
|
4244
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3947
4245
|
createdBy: {
|
3948
4246
|
select: ["id", "firstname", "lastname", "email"]
|
3949
4247
|
},
|
@@ -3952,7 +4250,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3952
4250
|
}
|
3953
4251
|
}
|
3954
4252
|
});
|
3955
|
-
const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
|
4253
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
|
3956
4254
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3957
4255
|
return {
|
3958
4256
|
availableLocales: availableLocalesResult,
|
@@ -3965,8 +4263,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3965
4263
|
* - Available status of the document for the current locale
|
3966
4264
|
*/
|
3967
4265
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3968
|
-
if (!document)
|
3969
|
-
return
|
4266
|
+
if (!document) {
|
4267
|
+
return {
|
4268
|
+
data: document,
|
4269
|
+
meta: {
|
4270
|
+
availableLocales: [],
|
4271
|
+
availableStatus: []
|
4272
|
+
}
|
4273
|
+
};
|
4274
|
+
}
|
3970
4275
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
3971
4276
|
if (!hasDraftAndPublish) {
|
3972
4277
|
opts.availableStatus = false;
|
@@ -4016,26 +4321,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
4016
4321
|
}, 0);
|
4017
4322
|
};
|
4018
4323
|
const { ApplicationError } = errors;
|
4019
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
4020
4324
|
const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
|
4021
4325
|
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
|
4022
4326
|
const omitIdField = omit("id");
|
4023
|
-
const emitEvent = async (uid2, event, document) => {
|
4024
|
-
const modelDef = strapi.getModel(uid2);
|
4025
|
-
const sanitizedDocument = await sanitize.sanitizers.defaultSanitizeOutput(
|
4026
|
-
{
|
4027
|
-
schema: modelDef,
|
4028
|
-
getModel(uid22) {
|
4029
|
-
return strapi.getModel(uid22);
|
4030
|
-
}
|
4031
|
-
},
|
4032
|
-
document
|
4033
|
-
);
|
4034
|
-
strapi.eventHub.emit(event, {
|
4035
|
-
model: modelDef.modelName,
|
4036
|
-
entry: sanitizedDocument
|
4037
|
-
});
|
4038
|
-
};
|
4039
4327
|
const documentManager = ({ strapi: strapi2 }) => {
|
4040
4328
|
return {
|
4041
4329
|
async findOne(id, uid2, opts = {}) {
|
@@ -4054,6 +4342,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4054
4342
|
} else if (opts.locale && opts.locale !== "*") {
|
4055
4343
|
where.locale = opts.locale;
|
4056
4344
|
}
|
4345
|
+
if (typeof opts.isPublished === "boolean") {
|
4346
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4347
|
+
}
|
4057
4348
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4058
4349
|
},
|
4059
4350
|
async findMany(opts, uid2) {
|
@@ -4087,10 +4378,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4087
4378
|
async clone(id, body, uid2) {
|
4088
4379
|
const populate = await buildDeepPopulate(uid2);
|
4089
4380
|
const params = {
|
4090
|
-
data:
|
4091
|
-
...omitIdField(body),
|
4092
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4093
|
-
},
|
4381
|
+
data: omitIdField(body),
|
4094
4382
|
populate
|
4095
4383
|
};
|
4096
4384
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4116,70 +4404,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4116
4404
|
return {};
|
4117
4405
|
},
|
4118
4406
|
// FIXME: handle relations
|
4119
|
-
async deleteMany(
|
4120
|
-
const
|
4121
|
-
|
4122
|
-
|
4123
|
-
}
|
4124
|
-
return { count: docs.length };
|
4407
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4408
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4409
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4410
|
+
});
|
4411
|
+
return { count: deletedEntries.length };
|
4125
4412
|
},
|
4126
4413
|
async publish(id, uid2, opts = {}) {
|
4127
4414
|
const populate = await buildDeepPopulate(uid2);
|
4128
4415
|
const params = { ...opts, populate };
|
4129
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4416
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4130
4417
|
},
|
4131
|
-
async publishMany(
|
4132
|
-
|
4133
|
-
|
4134
|
-
|
4135
|
-
|
4136
|
-
|
4137
|
-
|
4138
|
-
strapi2.getModel(uid2),
|
4139
|
-
document,
|
4140
|
-
void 0,
|
4141
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4142
|
-
document
|
4143
|
-
);
|
4144
|
-
})
|
4145
|
-
);
|
4146
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4147
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4148
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4149
|
-
const populate = await buildDeepPopulate(uid2);
|
4150
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4151
|
-
where: filters,
|
4152
|
-
data
|
4153
|
-
});
|
4154
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4155
|
-
where: filters,
|
4156
|
-
populate
|
4418
|
+
async publishMany(uid2, documentIds, locale) {
|
4419
|
+
return strapi2.db.transaction(async () => {
|
4420
|
+
const results = await Promise.all(
|
4421
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4422
|
+
);
|
4423
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4424
|
+
return publishedEntitiesCount;
|
4157
4425
|
});
|
4158
|
-
await Promise.all(
|
4159
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4160
|
-
);
|
4161
|
-
return publishedEntitiesCount;
|
4162
4426
|
},
|
4163
|
-
async unpublishMany(
|
4164
|
-
|
4165
|
-
return
|
4166
|
-
|
4167
|
-
|
4168
|
-
|
4169
|
-
|
4170
|
-
const populate = await buildDeepPopulate(uid2);
|
4171
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4172
|
-
where: filters,
|
4173
|
-
data
|
4174
|
-
});
|
4175
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4176
|
-
where: filters,
|
4177
|
-
populate
|
4427
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4428
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4429
|
+
return Promise.all(
|
4430
|
+
documentIds.map(
|
4431
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4432
|
+
)
|
4433
|
+
);
|
4178
4434
|
});
|
4179
|
-
|
4180
|
-
|
4181
|
-
);
|
4182
|
-
return unpublishedEntitiesCount;
|
4435
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4436
|
+
return { count: unpublishedEntitiesCount };
|
4183
4437
|
},
|
4184
4438
|
async unpublish(id, uid2, opts = {}) {
|
4185
4439
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4204,16 +4458,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4204
4458
|
}
|
4205
4459
|
return sumDraftCounts(document, uid2);
|
4206
4460
|
},
|
4207
|
-
async countManyEntriesDraftRelations(
|
4461
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4208
4462
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4209
4463
|
if (!hasRelations) {
|
4210
4464
|
return 0;
|
4211
4465
|
}
|
4466
|
+
let localeFilter = {};
|
4467
|
+
if (locale) {
|
4468
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4469
|
+
}
|
4212
4470
|
const entities = await strapi2.db.query(uid2).findMany({
|
4213
4471
|
populate,
|
4214
4472
|
where: {
|
4215
|
-
|
4216
|
-
...
|
4473
|
+
documentId: { $in: documentIds },
|
4474
|
+
...localeFilter
|
4217
4475
|
}
|
4218
4476
|
});
|
4219
4477
|
const totalNumberDraftRelations = entities.reduce(
|
@@ -4236,7 +4494,8 @@ const services = {
|
|
4236
4494
|
permission,
|
4237
4495
|
"populate-builder": populateBuilder$1,
|
4238
4496
|
uid,
|
4239
|
-
...history.services ? history.services : {}
|
4497
|
+
...history.services ? history.services : {},
|
4498
|
+
...preview.services ? preview.services : {}
|
4240
4499
|
};
|
4241
4500
|
const index = () => {
|
4242
4501
|
return {
|