@strapi/content-manager 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.e9122b401c96877b6707775c4f893660eab93ae3
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-BPvzFjM7.mjs → ComponentConfigurationPage-CpBFh6_r.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-CpBFh6_r.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-_zF8p6CY.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-_zF8p6CY.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-DacbqQ_f.mjs → EditConfigurationPage-CE_yavTi.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-CE_yavTi.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-_aG2DJSU.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-_aG2DJSU.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-DeTn7rAF.mjs} +59 -48
- package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-G9uNzwYL.js} +58 -49
- package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +1 -0
- package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-CnCKhI1R.mjs} +995 -795
- package/dist/_chunks/Field-CnCKhI1R.mjs.map +1 -0
- package/dist/_chunks/{Field-DmVKIAOo.js → Field-DDHUWEfV.js} +1041 -842
- package/dist/_chunks/Field-DDHUWEfV.js.map +1 -0
- package/dist/_chunks/{Form-CPZC9vWa.js → Form-DYETaKUX.js} +65 -45
- package/dist/_chunks/Form-DYETaKUX.js.map +1 -0
- package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-IvVVwqRL.mjs} +65 -44
- package/dist/_chunks/Form-IvVVwqRL.mjs.map +1 -0
- package/dist/_chunks/{History-Dmr9fmUA.mjs → History-BMunT-do.mjs} +148 -54
- package/dist/_chunks/History-BMunT-do.mjs.map +1 -0
- package/dist/_chunks/{History-DeAPlvtv.js → History-CnZDctSO.js} +149 -56
- package/dist/_chunks/History-CnZDctSO.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-BynalOp8.js} +67 -58
- package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-CDqkCxgV.mjs} +63 -53
- package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-I88Ouzoq.js} +126 -137
- package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +1 -0
- package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-_5gS-DOF.mjs} +123 -134
- package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BaWQ7HsA.js} +3 -3
- package/dist/_chunks/NoContentTypePage-BaWQ7HsA.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Dht-55hr.mjs} +3 -3
- package/dist/_chunks/NoContentTypePage-Dht-55hr.mjs.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-Bs8D5W_v.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-Bs8D5W_v.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-DCVUh5at.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-DCVUh5at.js.map} +1 -1
- package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-BPgFQeGj.js} +71 -62
- package/dist/_chunks/Relations-BPgFQeGj.js.map +1 -0
- package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-Chdt5qWc.mjs} +67 -57
- package/dist/_chunks/Relations-Chdt5qWc.mjs.map +1 -0
- package/dist/_chunks/{en-C-V1_90f.js → en-BVzUkPxZ.js} +16 -8
- package/dist/_chunks/{en-C-V1_90f.js.map → en-BVzUkPxZ.js.map} +1 -1
- package/dist/_chunks/{en-MBPul9Su.mjs → en-CPTj6CjC.mjs} +16 -8
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-CPTj6CjC.mjs.map} +1 -1
- package/dist/_chunks/{index-C6AH2hEl.js → index-BhbLFX4l.js} +1752 -903
- package/dist/_chunks/index-BhbLFX4l.js.map +1 -0
- package/dist/_chunks/{index-CwRRo1V9.mjs → index-D4UGPFZC.mjs} +1778 -928
- package/dist/_chunks/index-D4UGPFZC.mjs.map +1 -0
- package/dist/_chunks/{layout-B_SXLhqf.js → layout-CYA7s0qO.js} +45 -29
- package/dist/_chunks/layout-CYA7s0qO.js.map +1 -0
- package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-D4HI4_PS.mjs} +45 -27
- package/dist/_chunks/layout-D4HI4_PS.mjs.map +1 -0
- package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-1pXaYpBK.mjs} +2 -2
- package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-1pXaYpBK.mjs.map} +1 -1
- package/dist/_chunks/{relations-iBMa_OFG.js → relations-DDZ9OxNo.js} +2 -2
- package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-DDZ9OxNo.js.map} +1 -1
- 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 +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +8 -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 +1 -0
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +5 -8
- package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
- package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
- package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
- package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -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/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 +436 -281
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +444 -289
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/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 +8 -0
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/index.d.ts +1 -1
- package/dist/server/src/history/services/history.d.ts.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 +18 -39
- 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/services/document-manager.d.ts +13 -12
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +8 -29
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +18 -39
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts +8 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +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 +14 -15
- 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-DDS6H9HO.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
- package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
- package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
- package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
- package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
- package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
- package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
- package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
- package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
- package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
- package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
- package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
- package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
- package/dist/_chunks/layout-jIDzX0Fp.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/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";
|
@@ -54,7 +54,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
54
54
|
return ctx.forbidden();
|
55
55
|
}
|
56
56
|
const query = await permissionChecker2.sanitizeQuery(ctx.query);
|
57
|
-
const { results, pagination } = await getService(strapi2, "history").findVersionsPage({
|
57
|
+
const { results, pagination: pagination2 } = await getService(strapi2, "history").findVersionsPage({
|
58
58
|
query: {
|
59
59
|
...query,
|
60
60
|
...getValidPagination({ page: query.page, pageSize: query.pageSize })
|
@@ -73,7 +73,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
|
|
73
73
|
);
|
74
74
|
return {
|
75
75
|
data: sanitizedResults,
|
76
|
-
meta: { pagination }
|
76
|
+
meta: { pagination: pagination2 }
|
77
77
|
};
|
78
78
|
},
|
79
79
|
async restoreVersion(ctx) {
|
@@ -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,8 +316,14 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
308
316
|
});
|
309
317
|
},
|
310
318
|
async findVersionsPage(params) {
|
311
|
-
const
|
312
|
-
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
|
+
}
|
326
|
+
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
313
327
|
query.findPage({
|
314
328
|
...params.query,
|
315
329
|
where: {
|
@@ -408,7 +422,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
408
422
|
);
|
409
423
|
return {
|
410
424
|
results: formattedResults,
|
411
|
-
pagination
|
425
|
+
pagination: pagination2
|
412
426
|
};
|
413
427
|
},
|
414
428
|
async restoreVersion(versionId) {
|
@@ -464,13 +478,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
464
478
|
}
|
465
479
|
};
|
466
480
|
};
|
481
|
+
const shouldCreateHistoryVersion = (context) => {
|
482
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
483
|
+
return false;
|
484
|
+
}
|
485
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
486
|
+
return false;
|
487
|
+
}
|
488
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
489
|
+
return false;
|
490
|
+
}
|
491
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
492
|
+
return false;
|
493
|
+
}
|
494
|
+
return true;
|
495
|
+
};
|
496
|
+
const getSchemas = (uid2) => {
|
497
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
498
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
499
|
+
(currentComponentSchemas, key) => {
|
500
|
+
const fieldSchema = attributesSchema[key];
|
501
|
+
if (fieldSchema.type === "component") {
|
502
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
503
|
+
return {
|
504
|
+
...currentComponentSchemas,
|
505
|
+
[fieldSchema.component]: componentSchema
|
506
|
+
};
|
507
|
+
}
|
508
|
+
return currentComponentSchemas;
|
509
|
+
},
|
510
|
+
{}
|
511
|
+
);
|
512
|
+
return {
|
513
|
+
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
514
|
+
componentsSchemas
|
515
|
+
};
|
516
|
+
};
|
467
517
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
468
518
|
const state = {
|
469
519
|
deleteExpiredJob: null,
|
470
520
|
isInitialized: false
|
471
521
|
};
|
472
|
-
const query = strapi2.db.query(HISTORY_VERSION_UID);
|
473
|
-
const historyService = getService(strapi2, "history");
|
474
522
|
const serviceUtils = createServiceUtils({ strapi: strapi2 });
|
475
523
|
return {
|
476
524
|
async bootstrap() {
|
@@ -478,60 +526,53 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
478
526
|
return;
|
479
527
|
}
|
480
528
|
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
529
|
const result = await next();
|
492
|
-
|
530
|
+
if (!shouldCreateHistoryVersion(context)) {
|
531
|
+
return result;
|
532
|
+
}
|
533
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
493
534
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
494
|
-
const
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
535
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
536
|
+
if (!locales.length) {
|
537
|
+
return result;
|
538
|
+
}
|
539
|
+
const uid2 = context.contentType.uid;
|
540
|
+
const schemas = getSchemas(uid2);
|
541
|
+
const model = strapi2.getModel(uid2);
|
542
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
543
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
544
|
+
where: {
|
545
|
+
documentId,
|
546
|
+
...isLocalizedContentType ? { locale: { $in: locales } } : {},
|
547
|
+
...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
|
548
|
+
},
|
549
|
+
populate: serviceUtils.getDeepPopulate(
|
550
|
+
uid2,
|
551
|
+
true
|
552
|
+
/* use database syntax */
|
553
|
+
)
|
499
554
|
});
|
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
555
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
516
|
-
onCommit(() => {
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
556
|
+
onCommit(async () => {
|
557
|
+
for (const entry of localeEntries) {
|
558
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
559
|
+
await getService(strapi2, "history").createVersion({
|
560
|
+
contentType: uid2,
|
561
|
+
data: omit(FIELDS_TO_IGNORE, entry),
|
562
|
+
relatedDocumentId: documentId,
|
563
|
+
locale: entry.locale,
|
564
|
+
status,
|
565
|
+
...schemas
|
566
|
+
});
|
567
|
+
}
|
526
568
|
});
|
527
569
|
});
|
528
570
|
return result;
|
529
571
|
});
|
530
|
-
const retentionDays = serviceUtils.getRetentionDays();
|
531
572
|
state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
|
532
|
-
const retentionDaysInMilliseconds =
|
573
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
|
533
574
|
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
534
|
-
query.deleteMany({
|
575
|
+
strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
|
535
576
|
where: {
|
536
577
|
created_at: {
|
537
578
|
$lt: expirationDate.toISOString()
|
@@ -1163,6 +1204,11 @@ const { createPolicy } = policy;
|
|
1163
1204
|
const hasPermissions = createPolicy({
|
1164
1205
|
name: "plugin::content-manager.hasPermissions",
|
1165
1206
|
validator: validateHasPermissionsInput,
|
1207
|
+
/**
|
1208
|
+
* NOTE: Action aliases are currently not checked at this level (policy).
|
1209
|
+
* This is currently the intended behavior to avoid changing the behavior of API related permissions.
|
1210
|
+
* If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
|
1211
|
+
*/
|
1166
1212
|
handler(ctx, config = {}) {
|
1167
1213
|
const { actions = [], hasAtLeastOne = false } = config;
|
1168
1214
|
const { userAbility } = ctx.state;
|
@@ -1452,7 +1498,7 @@ const { PaginationError, ValidationError } = errors;
|
|
1452
1498
|
const TYPES = ["singleType", "collectionType"];
|
1453
1499
|
const kindSchema = yup$1.string().oneOf(TYPES).nullable();
|
1454
1500
|
const bulkActionInputSchema = yup$1.object({
|
1455
|
-
|
1501
|
+
documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
|
1456
1502
|
}).required();
|
1457
1503
|
const generateUIDInputSchema = yup$1.object({
|
1458
1504
|
contentTypeUID: yup$1.string().required(),
|
@@ -1551,15 +1597,49 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
|
|
1551
1597
|
}
|
1552
1598
|
}, body);
|
1553
1599
|
};
|
1554
|
-
const
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1600
|
+
const singleLocaleSchema = yup$1.string().nullable();
|
1601
|
+
const multipleLocaleSchema = yup$1.lazy(
|
1602
|
+
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1603
|
+
);
|
1604
|
+
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1605
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1606
|
+
const { allowMultipleLocales } = opts;
|
1607
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1608
|
+
const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1609
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1610
|
+
const schema = yup$1.object().shape({
|
1611
|
+
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1612
|
+
status: statusSchema
|
1613
|
+
});
|
1614
|
+
try {
|
1615
|
+
await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
|
1616
|
+
return { locale, status, ...rest };
|
1617
|
+
} catch (error) {
|
1618
|
+
throw new errors.ValidationError(`Validation error: ${error.message}`);
|
1561
1619
|
}
|
1562
|
-
|
1620
|
+
};
|
1621
|
+
const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
|
1622
|
+
const documentMetadata2 = getService$1("document-metadata");
|
1623
|
+
const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
|
1624
|
+
let {
|
1625
|
+
meta: { availableLocales, availableStatus }
|
1626
|
+
} = serviceOutput;
|
1627
|
+
const metadataSanitizer = permissionChecker2.sanitizeOutput;
|
1628
|
+
availableLocales = await async.map(
|
1629
|
+
availableLocales,
|
1630
|
+
async (localeDocument) => metadataSanitizer(localeDocument)
|
1631
|
+
);
|
1632
|
+
availableStatus = await async.map(
|
1633
|
+
availableStatus,
|
1634
|
+
async (statusDocument) => metadataSanitizer(statusDocument)
|
1635
|
+
);
|
1636
|
+
return {
|
1637
|
+
...serviceOutput,
|
1638
|
+
meta: {
|
1639
|
+
availableLocales,
|
1640
|
+
availableStatus
|
1641
|
+
}
|
1642
|
+
};
|
1563
1643
|
};
|
1564
1644
|
const createDocument = async (ctx, opts) => {
|
1565
1645
|
const { userAbility, user } = ctx.state;
|
@@ -1574,7 +1654,7 @@ const createDocument = async (ctx, opts) => {
|
|
1574
1654
|
const setCreator = setCreatorFields({ user });
|
1575
1655
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1576
1656
|
const sanitizedBody = await sanitizeFn(body);
|
1577
|
-
const { locale, status
|
1657
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1578
1658
|
return documentManager2.create(model, {
|
1579
1659
|
data: sanitizedBody,
|
1580
1660
|
locale,
|
@@ -1593,7 +1673,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1593
1673
|
}
|
1594
1674
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1595
1675
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1596
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1676
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1597
1677
|
const [documentVersion, documentExists] = await Promise.all([
|
1598
1678
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1599
1679
|
documentManager2.exists(model, id)
|
@@ -1631,8 +1711,8 @@ const collectionTypes = {
|
|
1631
1711
|
}
|
1632
1712
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1633
1713
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1634
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
1635
|
-
const { results: documents, pagination } = await documentManager2.findPage(
|
1714
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1715
|
+
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1636
1716
|
{ ...permissionQuery, populate, locale, status },
|
1637
1717
|
model
|
1638
1718
|
);
|
@@ -1653,21 +1733,20 @@ const collectionTypes = {
|
|
1653
1733
|
);
|
1654
1734
|
ctx.body = {
|
1655
1735
|
results,
|
1656
|
-
pagination
|
1736
|
+
pagination: pagination2
|
1657
1737
|
};
|
1658
1738
|
},
|
1659
1739
|
async findOne(ctx) {
|
1660
1740
|
const { userAbility } = ctx.state;
|
1661
1741
|
const { model, id } = ctx.params;
|
1662
1742
|
const documentManager2 = getService$1("document-manager");
|
1663
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1664
1743
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1665
1744
|
if (permissionChecker2.cannot.read()) {
|
1666
1745
|
return ctx.forbidden();
|
1667
1746
|
}
|
1668
1747
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1669
1748
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1670
|
-
const { locale, status
|
1749
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1671
1750
|
const version = await documentManager2.findOne(id, model, {
|
1672
1751
|
populate,
|
1673
1752
|
locale,
|
@@ -1678,9 +1757,11 @@ const collectionTypes = {
|
|
1678
1757
|
if (!exists) {
|
1679
1758
|
return ctx.notFound();
|
1680
1759
|
}
|
1681
|
-
const { meta } = await
|
1760
|
+
const { meta } = await formatDocumentWithMetadata(
|
1761
|
+
permissionChecker2,
|
1682
1762
|
model,
|
1683
|
-
|
1763
|
+
// @ts-expect-error TODO: fix
|
1764
|
+
{ documentId: id, locale, publishedAt: null },
|
1684
1765
|
{ availableLocales: true, availableStatus: false }
|
1685
1766
|
);
|
1686
1767
|
ctx.body = { data: {}, meta };
|
@@ -1690,12 +1771,11 @@ const collectionTypes = {
|
|
1690
1771
|
return ctx.forbidden();
|
1691
1772
|
}
|
1692
1773
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
1693
|
-
ctx.body = await
|
1774
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1694
1775
|
},
|
1695
1776
|
async create(ctx) {
|
1696
1777
|
const { userAbility } = ctx.state;
|
1697
1778
|
const { model } = ctx.params;
|
1698
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1699
1779
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1700
1780
|
const [totalEntries, document] = await Promise.all([
|
1701
1781
|
strapi.db.query(model).count(),
|
@@ -1703,7 +1783,7 @@ const collectionTypes = {
|
|
1703
1783
|
]);
|
1704
1784
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
1705
1785
|
ctx.status = 201;
|
1706
|
-
ctx.body = await
|
1786
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1707
1787
|
// Empty metadata as it's not relevant for a new document
|
1708
1788
|
availableLocales: false,
|
1709
1789
|
availableStatus: false
|
@@ -1717,25 +1797,23 @@ const collectionTypes = {
|
|
1717
1797
|
async update(ctx) {
|
1718
1798
|
const { userAbility } = ctx.state;
|
1719
1799
|
const { model } = ctx.params;
|
1720
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1721
1800
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1722
1801
|
const updatedVersion = await updateDocument(ctx);
|
1723
1802
|
const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
|
1724
|
-
ctx.body = await
|
1803
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
|
1725
1804
|
},
|
1726
1805
|
async clone(ctx) {
|
1727
1806
|
const { userAbility, user } = ctx.state;
|
1728
1807
|
const { model, sourceId: id } = ctx.params;
|
1729
1808
|
const { body } = ctx.request;
|
1730
1809
|
const documentManager2 = getService$1("document-manager");
|
1731
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1732
1810
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1733
1811
|
if (permissionChecker2.cannot.create()) {
|
1734
1812
|
return ctx.forbidden();
|
1735
1813
|
}
|
1736
1814
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1737
1815
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1738
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
1816
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1739
1817
|
const document = await documentManager2.findOne(id, model, {
|
1740
1818
|
populate,
|
1741
1819
|
locale,
|
@@ -1751,7 +1829,7 @@ const collectionTypes = {
|
|
1751
1829
|
const sanitizedBody = await sanitizeFn(body);
|
1752
1830
|
const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
|
1753
1831
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
|
1754
|
-
ctx.body = await
|
1832
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
|
1755
1833
|
// Empty metadata as it's not relevant for a new document
|
1756
1834
|
availableLocales: false,
|
1757
1835
|
availableStatus: false
|
@@ -1780,7 +1858,7 @@ const collectionTypes = {
|
|
1780
1858
|
}
|
1781
1859
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1782
1860
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1783
|
-
const { locale } = getDocumentLocaleAndStatus(ctx.query);
|
1861
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1784
1862
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1785
1863
|
if (documentLocales.length === 0) {
|
1786
1864
|
return ctx.notFound();
|
@@ -1802,7 +1880,6 @@ const collectionTypes = {
|
|
1802
1880
|
const { id, model } = ctx.params;
|
1803
1881
|
const { body } = ctx.request;
|
1804
1882
|
const documentManager2 = getService$1("document-manager");
|
1805
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1806
1883
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1807
1884
|
if (permissionChecker2.cannot.publish()) {
|
1808
1885
|
return ctx.forbidden();
|
@@ -1810,25 +1887,46 @@ const collectionTypes = {
|
|
1810
1887
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1811
1888
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1812
1889
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1813
|
-
|
1890
|
+
let document;
|
1891
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1892
|
+
const isCreate = isNil$1(id);
|
1893
|
+
if (isCreate) {
|
1894
|
+
if (permissionChecker2.cannot.create()) {
|
1895
|
+
throw new errors.ForbiddenError();
|
1896
|
+
}
|
1897
|
+
document = await createDocument(ctx, { populate });
|
1898
|
+
}
|
1899
|
+
const isUpdate = !isCreate;
|
1900
|
+
if (isUpdate) {
|
1901
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
1902
|
+
if (!document) {
|
1903
|
+
throw new errors.NotFoundError("Document not found");
|
1904
|
+
}
|
1905
|
+
if (permissionChecker2.can.update(document)) {
|
1906
|
+
await updateDocument(ctx);
|
1907
|
+
}
|
1908
|
+
}
|
1814
1909
|
if (permissionChecker2.cannot.publish(document)) {
|
1815
1910
|
throw new errors.ForbiddenError();
|
1816
1911
|
}
|
1817
|
-
const
|
1818
|
-
return documentManager2.publish(document.documentId, model, {
|
1912
|
+
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1819
1913
|
locale
|
1820
1914
|
// TODO: Allow setting creator fields on publish
|
1821
1915
|
// data: setCreatorFields({ user, isEdition: true })({}),
|
1822
1916
|
});
|
1917
|
+
if (!publishResult || publishResult.length === 0) {
|
1918
|
+
throw new errors.NotFoundError("Document not found or already published.");
|
1919
|
+
}
|
1920
|
+
return publishResult[0];
|
1823
1921
|
});
|
1824
1922
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
1825
|
-
ctx.body = await
|
1923
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
1826
1924
|
},
|
1827
1925
|
async bulkPublish(ctx) {
|
1828
1926
|
const { userAbility } = ctx.state;
|
1829
1927
|
const { model } = ctx.params;
|
1830
1928
|
const { body } = ctx.request;
|
1831
|
-
const {
|
1929
|
+
const { documentIds } = body;
|
1832
1930
|
await validateBulkActionInput(body);
|
1833
1931
|
const documentManager2 = getService$1("document-manager");
|
1834
1932
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1837,8 +1935,13 @@ const collectionTypes = {
|
|
1837
1935
|
}
|
1838
1936
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1839
1937
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1840
|
-
const
|
1841
|
-
|
1938
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1939
|
+
allowMultipleLocales: true
|
1940
|
+
});
|
1941
|
+
const entityPromises = documentIds.map(
|
1942
|
+
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1943
|
+
);
|
1944
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1842
1945
|
for (const entity of entities) {
|
1843
1946
|
if (!entity) {
|
1844
1947
|
return ctx.notFound();
|
@@ -1847,24 +1950,27 @@ const collectionTypes = {
|
|
1847
1950
|
return ctx.forbidden();
|
1848
1951
|
}
|
1849
1952
|
}
|
1850
|
-
const
|
1953
|
+
const count = await documentManager2.publishMany(model, documentIds, locale);
|
1851
1954
|
ctx.body = { count };
|
1852
1955
|
},
|
1853
1956
|
async bulkUnpublish(ctx) {
|
1854
1957
|
const { userAbility } = ctx.state;
|
1855
1958
|
const { model } = ctx.params;
|
1856
1959
|
const { body } = ctx.request;
|
1857
|
-
const {
|
1960
|
+
const { documentIds } = body;
|
1858
1961
|
await validateBulkActionInput(body);
|
1859
1962
|
const documentManager2 = getService$1("document-manager");
|
1860
1963
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1861
1964
|
if (permissionChecker2.cannot.unpublish()) {
|
1862
1965
|
return ctx.forbidden();
|
1863
1966
|
}
|
1864
|
-
const
|
1865
|
-
|
1866
|
-
|
1867
|
-
const
|
1967
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1968
|
+
allowMultipleLocales: true
|
1969
|
+
});
|
1970
|
+
const entityPromises = documentIds.map(
|
1971
|
+
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1972
|
+
);
|
1973
|
+
const entities = (await Promise.all(entityPromises)).flat();
|
1868
1974
|
for (const entity of entities) {
|
1869
1975
|
if (!entity) {
|
1870
1976
|
return ctx.notFound();
|
@@ -1873,7 +1979,8 @@ const collectionTypes = {
|
|
1873
1979
|
return ctx.forbidden();
|
1874
1980
|
}
|
1875
1981
|
}
|
1876
|
-
const
|
1982
|
+
const entitiesIds = entities.map((document) => document.documentId);
|
1983
|
+
const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
|
1877
1984
|
ctx.body = { count };
|
1878
1985
|
},
|
1879
1986
|
async unpublish(ctx) {
|
@@ -1883,7 +1990,6 @@ const collectionTypes = {
|
|
1883
1990
|
body: { discardDraft, ...body }
|
1884
1991
|
} = ctx.request;
|
1885
1992
|
const documentManager2 = getService$1("document-manager");
|
1886
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1887
1993
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1888
1994
|
if (permissionChecker2.cannot.unpublish()) {
|
1889
1995
|
return ctx.forbidden();
|
@@ -1893,7 +1999,7 @@ const collectionTypes = {
|
|
1893
1999
|
}
|
1894
2000
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1895
2001
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1896
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2002
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1897
2003
|
const document = await documentManager2.findOne(id, model, {
|
1898
2004
|
populate,
|
1899
2005
|
locale,
|
@@ -1915,7 +2021,7 @@ const collectionTypes = {
|
|
1915
2021
|
ctx.body = await async.pipe(
|
1916
2022
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
1917
2023
|
permissionChecker2.sanitizeOutput,
|
1918
|
-
(document2) =>
|
2024
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1919
2025
|
)(document);
|
1920
2026
|
});
|
1921
2027
|
},
|
@@ -1924,14 +2030,13 @@ const collectionTypes = {
|
|
1924
2030
|
const { id, model } = ctx.params;
|
1925
2031
|
const { body } = ctx.request;
|
1926
2032
|
const documentManager2 = getService$1("document-manager");
|
1927
|
-
const documentMetadata2 = getService$1("document-metadata");
|
1928
2033
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
1929
2034
|
if (permissionChecker2.cannot.discard()) {
|
1930
2035
|
return ctx.forbidden();
|
1931
2036
|
}
|
1932
2037
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1933
2038
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1934
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2039
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1935
2040
|
const document = await documentManager2.findOne(id, model, {
|
1936
2041
|
populate,
|
1937
2042
|
locale,
|
@@ -1946,14 +2051,14 @@ const collectionTypes = {
|
|
1946
2051
|
ctx.body = await async.pipe(
|
1947
2052
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
1948
2053
|
permissionChecker2.sanitizeOutput,
|
1949
|
-
(document2) =>
|
2054
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
1950
2055
|
)(document);
|
1951
2056
|
},
|
1952
2057
|
async bulkDelete(ctx) {
|
1953
2058
|
const { userAbility } = ctx.state;
|
1954
2059
|
const { model } = ctx.params;
|
1955
2060
|
const { query, body } = ctx.request;
|
1956
|
-
const {
|
2061
|
+
const { documentIds } = body;
|
1957
2062
|
await validateBulkActionInput(body);
|
1958
2063
|
const documentManager2 = getService$1("document-manager");
|
1959
2064
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
@@ -1961,14 +2066,22 @@ const collectionTypes = {
|
|
1961
2066
|
return ctx.forbidden();
|
1962
2067
|
}
|
1963
2068
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
1964
|
-
const
|
1965
|
-
const
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
2069
|
+
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2070
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2071
|
+
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2072
|
+
populate,
|
2073
|
+
locale
|
2074
|
+
});
|
2075
|
+
if (documentLocales.length === 0) {
|
2076
|
+
return ctx.notFound();
|
2077
|
+
}
|
2078
|
+
for (const document of documentLocales) {
|
2079
|
+
if (permissionChecker2.cannot.delete(document)) {
|
2080
|
+
return ctx.forbidden();
|
1969
2081
|
}
|
1970
|
-
}
|
1971
|
-
const
|
2082
|
+
}
|
2083
|
+
const localeDocumentsIds = documentLocales.map((document) => document.documentId);
|
2084
|
+
const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
|
1972
2085
|
ctx.body = { count };
|
1973
2086
|
},
|
1974
2087
|
async countDraftRelations(ctx) {
|
@@ -1981,7 +2094,7 @@ const collectionTypes = {
|
|
1981
2094
|
}
|
1982
2095
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1983
2096
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1984
|
-
const { locale, status
|
2097
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1985
2098
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
1986
2099
|
if (!entity) {
|
1987
2100
|
return ctx.notFound();
|
@@ -1996,7 +2109,7 @@ const collectionTypes = {
|
|
1996
2109
|
},
|
1997
2110
|
async countManyEntriesDraftRelations(ctx) {
|
1998
2111
|
const { userAbility } = ctx.state;
|
1999
|
-
const ids = ctx.request.query.
|
2112
|
+
const ids = ctx.request.query.documentIds;
|
2000
2113
|
const locale = ctx.request.query.locale;
|
2001
2114
|
const { model } = ctx.params;
|
2002
2115
|
const documentManager2 = getService$1("document-manager");
|
@@ -2004,16 +2117,16 @@ const collectionTypes = {
|
|
2004
2117
|
if (permissionChecker2.cannot.read()) {
|
2005
2118
|
return ctx.forbidden();
|
2006
2119
|
}
|
2007
|
-
const
|
2120
|
+
const documents = await documentManager2.findMany(
|
2008
2121
|
{
|
2009
2122
|
filters: {
|
2010
|
-
|
2123
|
+
documentId: ids
|
2011
2124
|
},
|
2012
2125
|
locale
|
2013
2126
|
},
|
2014
2127
|
model
|
2015
2128
|
);
|
2016
|
-
if (!
|
2129
|
+
if (!documents) {
|
2017
2130
|
return ctx.notFound();
|
2018
2131
|
}
|
2019
2132
|
const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
|
@@ -2204,20 +2317,13 @@ const sanitizeMainField = (model, mainField, userAbility) => {
|
|
2204
2317
|
userAbility,
|
2205
2318
|
model: model.uid
|
2206
2319
|
});
|
2207
|
-
|
2320
|
+
const isMainFieldListable = isListable(model, mainField);
|
2321
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2322
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2208
2323
|
return "id";
|
2209
2324
|
}
|
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";
|
2325
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2326
|
+
return "name";
|
2221
2327
|
}
|
2222
2328
|
return mainField;
|
2223
2329
|
};
|
@@ -2475,9 +2581,7 @@ const relations = {
|
|
2475
2581
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2476
2582
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2477
2583
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2478
|
-
ordering: "desc"
|
2479
|
-
page: ctx.request.query.page,
|
2480
|
-
pageSize: ctx.request.query.pageSize
|
2584
|
+
ordering: "desc"
|
2481
2585
|
});
|
2482
2586
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2483
2587
|
ctx.body = {
|
@@ -2509,7 +2613,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2509
2613
|
throw new errors.ForbiddenError();
|
2510
2614
|
}
|
2511
2615
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2512
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2616
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2513
2617
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2514
2618
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2515
2619
|
// Find the first document to check if it exists
|
@@ -2546,12 +2650,11 @@ const singleTypes = {
|
|
2546
2650
|
const { model } = ctx.params;
|
2547
2651
|
const { query = {} } = ctx.request;
|
2548
2652
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2549
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2550
2653
|
if (permissionChecker2.cannot.read()) {
|
2551
2654
|
return ctx.forbidden();
|
2552
2655
|
}
|
2553
2656
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2554
|
-
const { locale, status } = getDocumentLocaleAndStatus(query);
|
2657
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2555
2658
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2556
2659
|
if (!version) {
|
2557
2660
|
if (permissionChecker2.cannot.create()) {
|
@@ -2561,8 +2664,10 @@ const singleTypes = {
|
|
2561
2664
|
if (!document) {
|
2562
2665
|
return ctx.notFound();
|
2563
2666
|
}
|
2564
|
-
const { meta } = await
|
2667
|
+
const { meta } = await formatDocumentWithMetadata(
|
2668
|
+
permissionChecker2,
|
2565
2669
|
model,
|
2670
|
+
// @ts-expect-error - fix types
|
2566
2671
|
{ id: document.documentId, locale, publishedAt: null },
|
2567
2672
|
{ availableLocales: true, availableStatus: false }
|
2568
2673
|
);
|
@@ -2573,16 +2678,15 @@ const singleTypes = {
|
|
2573
2678
|
return ctx.forbidden();
|
2574
2679
|
}
|
2575
2680
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
|
2576
|
-
ctx.body = await
|
2681
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2577
2682
|
},
|
2578
2683
|
async createOrUpdate(ctx) {
|
2579
2684
|
const { userAbility } = ctx.state;
|
2580
2685
|
const { model } = ctx.params;
|
2581
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2582
2686
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2583
2687
|
const document = await createOrUpdateDocument(ctx);
|
2584
2688
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
|
2585
|
-
ctx.body = await
|
2689
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2586
2690
|
},
|
2587
2691
|
async delete(ctx) {
|
2588
2692
|
const { userAbility } = ctx.state;
|
@@ -2595,7 +2699,7 @@ const singleTypes = {
|
|
2595
2699
|
}
|
2596
2700
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2597
2701
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2598
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2702
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2599
2703
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2600
2704
|
populate,
|
2601
2705
|
locale
|
@@ -2618,7 +2722,6 @@ const singleTypes = {
|
|
2618
2722
|
const { model } = ctx.params;
|
2619
2723
|
const { query = {} } = ctx.request;
|
2620
2724
|
const documentManager2 = getService$1("document-manager");
|
2621
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2622
2725
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2623
2726
|
if (permissionChecker2.cannot.publish()) {
|
2624
2727
|
return ctx.forbidden();
|
@@ -2633,11 +2736,12 @@ const singleTypes = {
|
|
2633
2736
|
if (permissionChecker2.cannot.publish(document)) {
|
2634
2737
|
throw new errors.ForbiddenError();
|
2635
2738
|
}
|
2636
|
-
const { locale } = getDocumentLocaleAndStatus(document);
|
2637
|
-
|
2739
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2740
|
+
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2741
|
+
return publishResult.at(0);
|
2638
2742
|
});
|
2639
2743
|
const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
|
2640
|
-
ctx.body = await
|
2744
|
+
ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
|
2641
2745
|
},
|
2642
2746
|
async unpublish(ctx) {
|
2643
2747
|
const { userAbility } = ctx.state;
|
@@ -2647,7 +2751,6 @@ const singleTypes = {
|
|
2647
2751
|
query = {}
|
2648
2752
|
} = ctx.request;
|
2649
2753
|
const documentManager2 = getService$1("document-manager");
|
2650
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2651
2754
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2652
2755
|
if (permissionChecker2.cannot.unpublish()) {
|
2653
2756
|
return ctx.forbidden();
|
@@ -2656,7 +2759,7 @@ const singleTypes = {
|
|
2656
2759
|
return ctx.forbidden();
|
2657
2760
|
}
|
2658
2761
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2659
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2762
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2660
2763
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2661
2764
|
if (!document) {
|
2662
2765
|
return ctx.notFound();
|
@@ -2674,7 +2777,7 @@ const singleTypes = {
|
|
2674
2777
|
ctx.body = await async.pipe(
|
2675
2778
|
(document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
|
2676
2779
|
permissionChecker2.sanitizeOutput,
|
2677
|
-
(document2) =>
|
2780
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2678
2781
|
)(document);
|
2679
2782
|
});
|
2680
2783
|
},
|
@@ -2683,13 +2786,12 @@ const singleTypes = {
|
|
2683
2786
|
const { model } = ctx.params;
|
2684
2787
|
const { body, query = {} } = ctx.request;
|
2685
2788
|
const documentManager2 = getService$1("document-manager");
|
2686
|
-
const documentMetadata2 = getService$1("document-metadata");
|
2687
2789
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2688
2790
|
if (permissionChecker2.cannot.discard()) {
|
2689
2791
|
return ctx.forbidden();
|
2690
2792
|
}
|
2691
2793
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2692
|
-
const { locale } = getDocumentLocaleAndStatus(body);
|
2794
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2693
2795
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2694
2796
|
if (!document) {
|
2695
2797
|
return ctx.notFound();
|
@@ -2700,7 +2802,7 @@ const singleTypes = {
|
|
2700
2802
|
ctx.body = await async.pipe(
|
2701
2803
|
(document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
|
2702
2804
|
permissionChecker2.sanitizeOutput,
|
2703
|
-
(document2) =>
|
2805
|
+
(document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
|
2704
2806
|
)(document);
|
2705
2807
|
},
|
2706
2808
|
async countDraftRelations(ctx) {
|
@@ -2709,7 +2811,7 @@ const singleTypes = {
|
|
2709
2811
|
const { query } = ctx.request;
|
2710
2812
|
const documentManager2 = getService$1("document-manager");
|
2711
2813
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2712
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2814
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2713
2815
|
if (permissionChecker2.cannot.read()) {
|
2714
2816
|
return ctx.forbidden();
|
2715
2817
|
}
|
@@ -2730,7 +2832,7 @@ const uid$1 = {
|
|
2730
2832
|
async generateUID(ctx) {
|
2731
2833
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2732
2834
|
const { query = {} } = ctx.request;
|
2733
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2835
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2734
2836
|
await validateUIDField(contentTypeUID, field);
|
2735
2837
|
const uidService = getService$1("uid");
|
2736
2838
|
ctx.body = {
|
@@ -2742,7 +2844,7 @@ const uid$1 = {
|
|
2742
2844
|
ctx.request.body
|
2743
2845
|
);
|
2744
2846
|
const { query = {} } = ctx.request;
|
2745
|
-
const { locale } = getDocumentLocaleAndStatus(query);
|
2847
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2746
2848
|
await validateUIDField(contentTypeUID, field);
|
2747
2849
|
const uidService = getService$1("uid");
|
2748
2850
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -3385,12 +3487,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3385
3487
|
ability: userAbility,
|
3386
3488
|
model
|
3387
3489
|
});
|
3388
|
-
const
|
3490
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3491
|
+
const toSubject = (entity) => {
|
3492
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3493
|
+
};
|
3389
3494
|
const can = (action, entity, field) => {
|
3390
|
-
|
3495
|
+
const subject = toSubject(entity);
|
3496
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3497
|
+
return (
|
3498
|
+
// Test the original action to see if it passes
|
3499
|
+
userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
|
3500
|
+
aliases.some((alias) => userAbility.can(alias, subject, field))
|
3501
|
+
);
|
3391
3502
|
};
|
3392
3503
|
const cannot = (action, entity, field) => {
|
3393
|
-
|
3504
|
+
const subject = toSubject(entity);
|
3505
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3506
|
+
return (
|
3507
|
+
// Test both the original action
|
3508
|
+
userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
|
3509
|
+
aliases.every((alias) => userAbility.cannot(alias, subject, field))
|
3510
|
+
);
|
3394
3511
|
};
|
3395
3512
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3396
3513
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3533,7 +3650,7 @@ const permission = ({ strapi: strapi2 }) => ({
|
|
3533
3650
|
await strapi2.service("admin::permission").actionProvider.registerMany(actions);
|
3534
3651
|
}
|
3535
3652
|
});
|
3536
|
-
const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
|
3653
|
+
const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
|
3537
3654
|
const { isAnyToMany } = strapiUtils.relations;
|
3538
3655
|
const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
|
3539
3656
|
const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
|
@@ -3624,6 +3741,42 @@ const getDeepPopulate = (uid2, {
|
|
3624
3741
|
{}
|
3625
3742
|
);
|
3626
3743
|
};
|
3744
|
+
const getValidatableFieldsPopulate = (uid2, {
|
3745
|
+
initialPopulate = {},
|
3746
|
+
countMany = false,
|
3747
|
+
countOne = false,
|
3748
|
+
maxLevel = Infinity
|
3749
|
+
} = {}, level = 1) => {
|
3750
|
+
if (level > maxLevel) {
|
3751
|
+
return {};
|
3752
|
+
}
|
3753
|
+
const model = strapi.getModel(uid2);
|
3754
|
+
return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
|
3755
|
+
if (!getDoesAttributeRequireValidation(attribute)) {
|
3756
|
+
return populateAcc;
|
3757
|
+
}
|
3758
|
+
if (isScalarAttribute(attribute)) {
|
3759
|
+
return merge(populateAcc, {
|
3760
|
+
[attributeName]: true
|
3761
|
+
});
|
3762
|
+
}
|
3763
|
+
return merge(
|
3764
|
+
populateAcc,
|
3765
|
+
getPopulateFor(
|
3766
|
+
attributeName,
|
3767
|
+
model,
|
3768
|
+
{
|
3769
|
+
// @ts-expect-error - improve types
|
3770
|
+
initialPopulate: initialPopulate?.[attributeName],
|
3771
|
+
countMany,
|
3772
|
+
countOne,
|
3773
|
+
maxLevel
|
3774
|
+
},
|
3775
|
+
level
|
3776
|
+
)
|
3777
|
+
);
|
3778
|
+
}, {});
|
3779
|
+
};
|
3627
3780
|
const getDeepPopulateDraftCount = (uid2) => {
|
3628
3781
|
const model = strapi.getModel(uid2);
|
3629
3782
|
let hasRelations = false;
|
@@ -3631,6 +3784,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3631
3784
|
const attribute = model.attributes[attributeName];
|
3632
3785
|
switch (attribute.type) {
|
3633
3786
|
case "relation": {
|
3787
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
3788
|
+
if (isMorphRelation) {
|
3789
|
+
break;
|
3790
|
+
}
|
3634
3791
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3635
3792
|
populateAcc[attributeName] = {
|
3636
3793
|
count: true,
|
@@ -3645,22 +3802,24 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3645
3802
|
attribute.component
|
3646
3803
|
);
|
3647
3804
|
if (childHasRelations) {
|
3648
|
-
populateAcc[attributeName] = {
|
3805
|
+
populateAcc[attributeName] = {
|
3806
|
+
populate: populate2
|
3807
|
+
};
|
3649
3808
|
hasRelations = true;
|
3650
3809
|
}
|
3651
3810
|
break;
|
3652
3811
|
}
|
3653
3812
|
case "dynamiczone": {
|
3654
|
-
const
|
3655
|
-
const { populate:
|
3656
|
-
if (
|
3813
|
+
const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
|
3814
|
+
const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
|
3815
|
+
if (componentHasRelations) {
|
3657
3816
|
hasRelations = true;
|
3658
|
-
return
|
3817
|
+
return { ...acc, [componentUID]: { populate: componentPopulate } };
|
3659
3818
|
}
|
3660
3819
|
return acc;
|
3661
3820
|
}, {});
|
3662
|
-
if (!isEmpty(
|
3663
|
-
populateAcc[attributeName] = {
|
3821
|
+
if (!isEmpty(dzPopulateFragment)) {
|
3822
|
+
populateAcc[attributeName] = { on: dzPopulateFragment };
|
3664
3823
|
}
|
3665
3824
|
break;
|
3666
3825
|
}
|
@@ -3852,41 +4011,70 @@ const AVAILABLE_STATUS_FIELDS = [
|
|
3852
4011
|
"updatedBy",
|
3853
4012
|
"status"
|
3854
4013
|
];
|
3855
|
-
const AVAILABLE_LOCALES_FIELDS = [
|
4014
|
+
const AVAILABLE_LOCALES_FIELDS = [
|
4015
|
+
"id",
|
4016
|
+
"locale",
|
4017
|
+
"updatedAt",
|
4018
|
+
"createdAt",
|
4019
|
+
"status",
|
4020
|
+
"publishedAt",
|
4021
|
+
"documentId"
|
4022
|
+
];
|
3856
4023
|
const CONTENT_MANAGER_STATUS = {
|
3857
4024
|
PUBLISHED: "published",
|
3858
4025
|
DRAFT: "draft",
|
3859
4026
|
MODIFIED: "modified"
|
3860
4027
|
};
|
3861
|
-
const
|
3862
|
-
if (!
|
4028
|
+
const getIsVersionLatestModification = (version, otherVersion) => {
|
4029
|
+
if (!version || !version.updatedAt) {
|
3863
4030
|
return false;
|
3864
4031
|
}
|
3865
|
-
const
|
3866
|
-
const
|
3867
|
-
|
3868
|
-
return difference2 <= threshold;
|
4032
|
+
const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
|
4033
|
+
const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
|
4034
|
+
return versionUpdatedAt > otherUpdatedAt;
|
3869
4035
|
};
|
3870
4036
|
const documentMetadata = ({ strapi: strapi2 }) => ({
|
3871
4037
|
/**
|
3872
4038
|
* Returns available locales of a document for the current status
|
3873
4039
|
*/
|
3874
|
-
getAvailableLocales(uid2, version, allVersions) {
|
4040
|
+
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3875
4041
|
const versionsByLocale = groupBy("locale", allVersions);
|
3876
4042
|
delete versionsByLocale[version.locale];
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
4043
|
+
const model = strapi2.getModel(uid2);
|
4044
|
+
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
4045
|
+
const traversalFunction = async (localeVersion) => traverseEntity(
|
4046
|
+
({ key }, { remove }) => {
|
4047
|
+
if (keysToKeep.includes(key)) {
|
4048
|
+
return;
|
4049
|
+
}
|
4050
|
+
remove(key);
|
4051
|
+
},
|
4052
|
+
{ schema: model, getModel: strapi2.getModel.bind(strapi2) },
|
4053
|
+
// @ts-expect-error fix types DocumentVersion incompatible with Data
|
4054
|
+
localeVersion
|
4055
|
+
);
|
4056
|
+
const mappingResult = await async.map(
|
4057
|
+
Object.values(versionsByLocale),
|
4058
|
+
async (localeVersions) => {
|
4059
|
+
const mappedLocaleVersions = await async.map(
|
4060
|
+
localeVersions,
|
4061
|
+
traversalFunction
|
4062
|
+
);
|
4063
|
+
if (!contentTypes$1.hasDraftAndPublish(model)) {
|
4064
|
+
return mappedLocaleVersions[0];
|
4065
|
+
}
|
4066
|
+
const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
|
4067
|
+
const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
|
4068
|
+
if (!draftVersion) {
|
4069
|
+
return;
|
4070
|
+
}
|
4071
|
+
return {
|
4072
|
+
...draftVersion,
|
4073
|
+
status: this.getStatus(draftVersion, otherVersions)
|
4074
|
+
};
|
3880
4075
|
}
|
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);
|
4076
|
+
);
|
4077
|
+
return mappingResult.filter(Boolean);
|
3890
4078
|
},
|
3891
4079
|
/**
|
3892
4080
|
* Returns available status of a document for the current locale
|
@@ -3924,26 +4112,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3924
4112
|
});
|
3925
4113
|
},
|
3926
4114
|
getStatus(version, otherDocumentStatuses) {
|
3927
|
-
|
3928
|
-
|
3929
|
-
|
4115
|
+
let draftVersion;
|
4116
|
+
let publishedVersion;
|
4117
|
+
if (version.publishedAt) {
|
4118
|
+
publishedVersion = version;
|
4119
|
+
} else {
|
4120
|
+
draftVersion = version;
|
3930
4121
|
}
|
3931
|
-
|
3932
|
-
|
3933
|
-
|
3934
|
-
|
3935
|
-
|
4122
|
+
const otherVersion = otherDocumentStatuses?.at(0);
|
4123
|
+
if (otherVersion?.publishedAt) {
|
4124
|
+
publishedVersion = otherVersion;
|
4125
|
+
} else if (otherVersion) {
|
4126
|
+
draftVersion = otherVersion;
|
3936
4127
|
}
|
3937
|
-
if (
|
4128
|
+
if (!draftVersion)
|
3938
4129
|
return CONTENT_MANAGER_STATUS.PUBLISHED;
|
3939
|
-
|
3940
|
-
|
4130
|
+
if (!publishedVersion)
|
4131
|
+
return CONTENT_MANAGER_STATUS.DRAFT;
|
4132
|
+
const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
|
4133
|
+
return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
|
3941
4134
|
},
|
4135
|
+
// TODO is it necessary to return metadata on every page of the CM
|
4136
|
+
// We could refactor this so the locales are only loaded when they're
|
4137
|
+
// needed. e.g. in the bulk locale action modal.
|
3942
4138
|
async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
|
4139
|
+
const populate = getValidatableFieldsPopulate(uid2);
|
3943
4140
|
const versions = await strapi2.db.query(uid2).findMany({
|
3944
4141
|
where: { documentId: version.documentId },
|
3945
|
-
select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
|
3946
4142
|
populate: {
|
4143
|
+
// Populate only fields that require validation for bulk locale actions
|
4144
|
+
...populate,
|
4145
|
+
// NOTE: creator fields are selected in this way to avoid exposing sensitive data
|
3947
4146
|
createdBy: {
|
3948
4147
|
select: ["id", "firstname", "lastname", "email"]
|
3949
4148
|
},
|
@@ -3952,7 +4151,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3952
4151
|
}
|
3953
4152
|
}
|
3954
4153
|
});
|
3955
|
-
const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
|
4154
|
+
const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
|
3956
4155
|
const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
|
3957
4156
|
return {
|
3958
4157
|
availableLocales: availableLocalesResult,
|
@@ -3965,8 +4164,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3965
4164
|
* - Available status of the document for the current locale
|
3966
4165
|
*/
|
3967
4166
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
3968
|
-
if (!document)
|
3969
|
-
return
|
4167
|
+
if (!document) {
|
4168
|
+
return {
|
4169
|
+
data: document,
|
4170
|
+
meta: {
|
4171
|
+
availableLocales: [],
|
4172
|
+
availableStatus: []
|
4173
|
+
}
|
4174
|
+
};
|
4175
|
+
}
|
3970
4176
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
3971
4177
|
if (!hasDraftAndPublish) {
|
3972
4178
|
opts.availableStatus = false;
|
@@ -4016,26 +4222,9 @@ const sumDraftCounts = (entity, uid2) => {
|
|
4016
4222
|
}, 0);
|
4017
4223
|
};
|
4018
4224
|
const { ApplicationError } = errors;
|
4019
|
-
const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
|
4020
4225
|
const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
|
4021
4226
|
const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
|
4022
4227
|
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
4228
|
const documentManager = ({ strapi: strapi2 }) => {
|
4040
4229
|
return {
|
4041
4230
|
async findOne(id, uid2, opts = {}) {
|
@@ -4054,6 +4243,9 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4054
4243
|
} else if (opts.locale && opts.locale !== "*") {
|
4055
4244
|
where.locale = opts.locale;
|
4056
4245
|
}
|
4246
|
+
if (typeof opts.isPublished === "boolean") {
|
4247
|
+
where.publishedAt = { $notNull: opts.isPublished };
|
4248
|
+
}
|
4057
4249
|
return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
|
4058
4250
|
},
|
4059
4251
|
async findMany(opts, uid2) {
|
@@ -4061,20 +4253,16 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4061
4253
|
return strapi2.documents(uid2).findMany(params);
|
4062
4254
|
},
|
4063
4255
|
async findPage(opts, uid2) {
|
4064
|
-
const
|
4065
|
-
|
4256
|
+
const params = pagination.withDefaultPagination(opts || {}, {
|
4257
|
+
maxLimit: 1e3
|
4258
|
+
});
|
4066
4259
|
const [documents, total = 0] = await Promise.all([
|
4067
|
-
strapi2.documents(uid2).findMany(
|
4068
|
-
strapi2.documents(uid2).count(
|
4260
|
+
strapi2.documents(uid2).findMany(params),
|
4261
|
+
strapi2.documents(uid2).count(params)
|
4069
4262
|
]);
|
4070
4263
|
return {
|
4071
4264
|
results: documents,
|
4072
|
-
pagination:
|
4073
|
-
page,
|
4074
|
-
pageSize,
|
4075
|
-
pageCount: Math.ceil(total / pageSize),
|
4076
|
-
total
|
4077
|
-
}
|
4265
|
+
pagination: pagination.transformPagedPaginationInfo(params, total)
|
4078
4266
|
};
|
4079
4267
|
},
|
4080
4268
|
async create(uid2, opts = {}) {
|
@@ -4091,10 +4279,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4091
4279
|
async clone(id, body, uid2) {
|
4092
4280
|
const populate = await buildDeepPopulate(uid2);
|
4093
4281
|
const params = {
|
4094
|
-
data:
|
4095
|
-
...omitIdField(body),
|
4096
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4097
|
-
},
|
4282
|
+
data: omitIdField(body),
|
4098
4283
|
populate
|
4099
4284
|
};
|
4100
4285
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|
@@ -4120,70 +4305,36 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4120
4305
|
return {};
|
4121
4306
|
},
|
4122
4307
|
// FIXME: handle relations
|
4123
|
-
async deleteMany(
|
4124
|
-
const
|
4125
|
-
|
4126
|
-
|
4127
|
-
}
|
4128
|
-
return { count: docs.length };
|
4308
|
+
async deleteMany(documentIds, uid2, opts = {}) {
|
4309
|
+
const deletedEntries = await strapi2.db.transaction(async () => {
|
4310
|
+
return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
|
4311
|
+
});
|
4312
|
+
return { count: deletedEntries.length };
|
4129
4313
|
},
|
4130
4314
|
async publish(id, uid2, opts = {}) {
|
4131
4315
|
const populate = await buildDeepPopulate(uid2);
|
4132
4316
|
const params = { ...opts, populate };
|
4133
|
-
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries
|
4317
|
+
return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
|
4134
4318
|
},
|
4135
|
-
async publishMany(
|
4136
|
-
|
4137
|
-
|
4138
|
-
|
4139
|
-
|
4140
|
-
|
4141
|
-
|
4142
|
-
strapi2.getModel(uid2),
|
4143
|
-
document,
|
4144
|
-
void 0,
|
4145
|
-
// @ts-expect-error - FIXME: entity here is unnecessary
|
4146
|
-
document
|
4147
|
-
);
|
4148
|
-
})
|
4149
|
-
);
|
4150
|
-
const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
|
4151
|
-
const filters = { id: { $in: entitiesToPublish } };
|
4152
|
-
const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
|
4153
|
-
const populate = await buildDeepPopulate(uid2);
|
4154
|
-
const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4155
|
-
where: filters,
|
4156
|
-
data
|
4157
|
-
});
|
4158
|
-
const publishedEntities = await strapi2.db.query(uid2).findMany({
|
4159
|
-
where: filters,
|
4160
|
-
populate
|
4319
|
+
async publishMany(uid2, documentIds, locale) {
|
4320
|
+
return strapi2.db.transaction(async () => {
|
4321
|
+
const results = await Promise.all(
|
4322
|
+
documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
|
4323
|
+
);
|
4324
|
+
const publishedEntitiesCount = results.flat().filter(Boolean).length;
|
4325
|
+
return publishedEntitiesCount;
|
4161
4326
|
});
|
4162
|
-
await Promise.all(
|
4163
|
-
publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
|
4164
|
-
);
|
4165
|
-
return publishedEntitiesCount;
|
4166
4327
|
},
|
4167
|
-
async unpublishMany(
|
4168
|
-
|
4169
|
-
return
|
4170
|
-
|
4171
|
-
|
4172
|
-
|
4173
|
-
|
4174
|
-
const populate = await buildDeepPopulate(uid2);
|
4175
|
-
const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
|
4176
|
-
where: filters,
|
4177
|
-
data
|
4178
|
-
});
|
4179
|
-
const unpublishedEntities = await strapi2.db.query(uid2).findMany({
|
4180
|
-
where: filters,
|
4181
|
-
populate
|
4328
|
+
async unpublishMany(documentIds, uid2, opts = {}) {
|
4329
|
+
const unpublishedEntries = await strapi2.db.transaction(async () => {
|
4330
|
+
return Promise.all(
|
4331
|
+
documentIds.map(
|
4332
|
+
(id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
|
4333
|
+
)
|
4334
|
+
);
|
4182
4335
|
});
|
4183
|
-
|
4184
|
-
|
4185
|
-
);
|
4186
|
-
return unpublishedEntitiesCount;
|
4336
|
+
const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
|
4337
|
+
return { count: unpublishedEntitiesCount };
|
4187
4338
|
},
|
4188
4339
|
async unpublish(id, uid2, opts = {}) {
|
4189
4340
|
const populate = await buildDeepPopulate(uid2);
|
@@ -4208,16 +4359,20 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4208
4359
|
}
|
4209
4360
|
return sumDraftCounts(document, uid2);
|
4210
4361
|
},
|
4211
|
-
async countManyEntriesDraftRelations(
|
4362
|
+
async countManyEntriesDraftRelations(documentIds, uid2, locale) {
|
4212
4363
|
const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
|
4213
4364
|
if (!hasRelations) {
|
4214
4365
|
return 0;
|
4215
4366
|
}
|
4367
|
+
let localeFilter = {};
|
4368
|
+
if (locale) {
|
4369
|
+
localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
|
4370
|
+
}
|
4216
4371
|
const entities = await strapi2.db.query(uid2).findMany({
|
4217
4372
|
populate,
|
4218
4373
|
where: {
|
4219
|
-
|
4220
|
-
...
|
4374
|
+
documentId: { $in: documentIds },
|
4375
|
+
...localeFilter
|
4221
4376
|
}
|
4222
4377
|
});
|
4223
4378
|
const totalNumberDraftRelations = entities.reduce(
|