@strapi/content-manager 0.0.0-experimental.d53e940834bf72ddc725f1d2fd36dac9abec30cb → 0.0.0-experimental.d834c9e658d1fb037e6da1105150593521c667cc

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.
Files changed (115) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-D_M8iBw5.js} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-D_M8iBw5.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-qemkOlnj.mjs} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-qemkOlnj.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-BePwPuHy.js} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-BePwPuHy.js.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-CjUrEewK.mjs} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-CjUrEewK.mjs.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-B-RJeiJD.js} +19 -8
  11. package/dist/_chunks/EditViewPage-B-RJeiJD.js.map +1 -0
  12. package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-De8GyU8P.mjs} +19 -8
  13. package/dist/_chunks/EditViewPage-De8GyU8P.mjs.map +1 -0
  14. package/dist/_chunks/{Field-Boxf9Ajp.js → Field-dq8Tg1M_.js} +175 -84
  15. package/dist/_chunks/Field-dq8Tg1M_.js.map +1 -0
  16. package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-pb2o8uBe.mjs} +177 -86
  17. package/dist/_chunks/Field-pb2o8uBe.mjs.map +1 -0
  18. package/dist/_chunks/{Form-y5g1SRsh.js → Form-DGIf4jQU.js} +22 -11
  19. package/dist/_chunks/Form-DGIf4jQU.js.map +1 -0
  20. package/dist/_chunks/{Form-DHrru2AV.mjs → Form-DJn0Dxha.mjs} +22 -11
  21. package/dist/_chunks/Form-DJn0Dxha.mjs.map +1 -0
  22. package/dist/_chunks/{History-Bru_KoeP.mjs → History-BowL3JKP.mjs} +44 -19
  23. package/dist/_chunks/History-BowL3JKP.mjs.map +1 -0
  24. package/dist/_chunks/{History-CqN6K7SX.js → History-Dh2NEHnR.js} +44 -19
  25. package/dist/_chunks/History-Dh2NEHnR.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-BpVOB-hn.mjs} +20 -8
  27. package/dist/_chunks/ListConfigurationPage-BpVOB-hn.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-BxYCWz9e.js} +20 -8
  29. package/dist/_chunks/ListConfigurationPage-BxYCWz9e.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-4XsciqHZ.js} +21 -7
  31. package/dist/_chunks/ListViewPage-4XsciqHZ.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-CXFUjZQC.mjs} +22 -8
  33. package/dist/_chunks/ListViewPage-CXFUjZQC.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-C8OpoHeU.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-C8OpoHeU.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-DuhOTp3x.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-DuhOTp3x.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-DVz3mzDz.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-DVz3mzDz.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-y_r7DVA2.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-y_r7DVA2.js.map} +1 -1
  42. package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-CVNLrn1Y.mjs} +4 -4
  43. package/dist/_chunks/Relations-CVNLrn1Y.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-DPFCAa7b.js} +4 -4
  45. package/dist/_chunks/Relations-DPFCAa7b.js.map +1 -0
  46. package/dist/_chunks/{en-Ux26r5pl.mjs → en-BrCTWlZv.mjs} +5 -4
  47. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  48. package/dist/_chunks/{en-fbKQxLGn.js → en-uOUIxfcQ.js} +5 -4
  49. package/dist/_chunks/{en-fbKQxLGn.js.map → en-uOUIxfcQ.js.map} +1 -1
  50. package/dist/_chunks/{index-DVPWZkbS.js → index-C3fJE-1-.js} +368 -168
  51. package/dist/_chunks/index-C3fJE-1-.js.map +1 -0
  52. package/dist/_chunks/{index-DJXJw9V5.mjs → index-DiMrfcfy.mjs} +387 -187
  53. package/dist/_chunks/index-DiMrfcfy.mjs.map +1 -0
  54. package/dist/_chunks/{layout-Dm6fbiQj.js → layout-C788OmNr.js} +22 -10
  55. package/dist/_chunks/layout-C788OmNr.js.map +1 -0
  56. package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-ls3gxfpH.mjs} +23 -11
  57. package/dist/_chunks/layout-ls3gxfpH.mjs.map +1 -0
  58. package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-CLcOmGO0.mjs} +2 -2
  59. package/dist/_chunks/{relations-BH_kBSJ0.mjs.map → relations-CLcOmGO0.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CKnpRgrN.js → relations-DYeotliT.js} +2 -2
  61. package/dist/_chunks/{relations-CKnpRgrN.js.map → relations-DYeotliT.js.map} +1 -1
  62. package/dist/admin/index.js +1 -1
  63. package/dist/admin/index.mjs +4 -4
  64. package/dist/admin/src/history/index.d.ts +3 -0
  65. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  66. package/dist/admin/src/index.d.ts +1 -0
  67. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  68. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  69. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  70. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  71. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +10 -22
  72. package/dist/admin/src/services/api.d.ts +1 -1
  73. package/dist/admin/src/services/components.d.ts +2 -2
  74. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  75. package/dist/admin/src/services/documents.d.ts +16 -16
  76. package/dist/admin/src/services/init.d.ts +1 -1
  77. package/dist/admin/src/services/relations.d.ts +2 -2
  78. package/dist/admin/src/services/uid.d.ts +3 -3
  79. package/dist/admin/src/utils/validation.d.ts +4 -1
  80. package/dist/server/index.js +165 -105
  81. package/dist/server/index.js.map +1 -1
  82. package/dist/server/index.mjs +166 -106
  83. package/dist/server/index.mjs.map +1 -1
  84. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  85. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  86. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  87. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  88. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  89. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  90. package/dist/server/src/history/services/utils.d.ts +1 -1
  91. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  92. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  93. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  94. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  95. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  96. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  97. package/package.json +8 -8
  98. package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
  99. package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
  100. package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
  101. package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
  102. package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
  103. package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
  104. package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
  105. package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
  106. package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
  107. package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
  108. package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
  109. package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
  110. package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
  111. package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
  112. package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
  113. package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
  114. package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
  115. package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
@@ -226,20 +226,25 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
226
226
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
227
227
  return documentMetadataService.getStatus(document, meta.availableStatus);
228
228
  };
229
- const getDeepPopulate2 = (uid2) => {
229
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
230
230
  const model = strapi2.getModel(uid2);
231
231
  const attributes = Object.entries(model.attributes);
232
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
232
233
  return attributes.reduce((acc, [attributeName, attribute]) => {
233
234
  switch (attribute.type) {
234
235
  case "relation": {
236
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
237
+ if (isMorphRelation) {
238
+ break;
239
+ }
235
240
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
236
241
  if (isVisible2) {
237
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
242
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
238
243
  }
239
244
  break;
240
245
  }
241
246
  case "media": {
242
- acc[attributeName] = { fields: ["id"] };
247
+ acc[attributeName] = { [fieldSelector]: ["id"] };
243
248
  break;
244
249
  }
245
250
  case "component": {
@@ -490,6 +495,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
490
495
  }
491
496
  };
492
497
  };
498
+ const shouldCreateHistoryVersion = (context) => {
499
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
500
+ return false;
501
+ }
502
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
503
+ return false;
504
+ }
505
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
506
+ return false;
507
+ }
508
+ if (!context.contentType.uid.startsWith("api::")) {
509
+ return false;
510
+ }
511
+ return true;
512
+ };
513
+ const getSchemas = (uid2) => {
514
+ const attributesSchema = strapi.getModel(uid2).attributes;
515
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
516
+ (currentComponentSchemas, key) => {
517
+ const fieldSchema = attributesSchema[key];
518
+ if (fieldSchema.type === "component") {
519
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
520
+ return {
521
+ ...currentComponentSchemas,
522
+ [fieldSchema.component]: componentSchema
523
+ };
524
+ }
525
+ return currentComponentSchemas;
526
+ },
527
+ {}
528
+ );
529
+ return {
530
+ schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
531
+ componentsSchemas
532
+ };
533
+ };
493
534
  const createLifecyclesService = ({ strapi: strapi2 }) => {
494
535
  const state = {
495
536
  deleteExpiredJob: null,
@@ -502,63 +543,43 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
502
543
  return;
503
544
  }
504
545
  strapi2.documents.use(async (context, next) => {
505
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
506
- return next();
507
- }
508
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
509
- return next();
510
- }
511
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
512
- return next();
513
- }
514
- const contentTypeUid = context.contentType.uid;
515
- if (!contentTypeUid.startsWith("api::")) {
516
- return next();
517
- }
518
546
  const result = await next();
519
- const documentContext = {
520
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
521
- locale: context.params?.locale
522
- };
547
+ if (!shouldCreateHistoryVersion(context)) {
548
+ return result;
549
+ }
550
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
523
551
  const defaultLocale = await serviceUtils.getDefaultLocale();
524
- const locale = documentContext.locale || defaultLocale;
525
- if (Array.isArray(locale)) {
526
- strapi2.log.warn(
527
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
528
- );
529
- return next();
552
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
553
+ if (!locales.length) {
554
+ return result;
530
555
  }
531
- const document = await strapi2.documents(contentTypeUid).findOne({
532
- documentId: documentContext.documentId,
533
- locale,
534
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
556
+ const uid2 = context.contentType.uid;
557
+ const schemas = getSchemas(uid2);
558
+ const localeEntries = await strapi2.db.query(uid2).findMany({
559
+ where: {
560
+ documentId,
561
+ locale: { $in: locales },
562
+ publishedAt: null
563
+ },
564
+ populate: serviceUtils.getDeepPopulate(
565
+ uid2,
566
+ true
567
+ /* use database syntax */
568
+ )
535
569
  });
536
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
537
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
538
- const componentsSchemas = Object.keys(
539
- attributesSchema
540
- ).reduce((currentComponentSchemas, key) => {
541
- const fieldSchema = attributesSchema[key];
542
- if (fieldSchema.type === "component") {
543
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
544
- return {
545
- ...currentComponentSchemas,
546
- [fieldSchema.component]: componentSchema
547
- };
548
- }
549
- return currentComponentSchemas;
550
- }, {});
551
570
  await strapi2.db.transaction(async ({ onCommit }) => {
552
- onCommit(() => {
553
- getService(strapi2, "history").createVersion({
554
- contentType: contentTypeUid,
555
- data: fp.omit(FIELDS_TO_IGNORE, document),
556
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
557
- componentsSchemas,
558
- relatedDocumentId: documentContext.documentId,
559
- locale,
560
- status
561
- });
571
+ onCommit(async () => {
572
+ for (const entry of localeEntries) {
573
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
574
+ await getService(strapi2, "history").createVersion({
575
+ contentType: uid2,
576
+ data: fp.omit(FIELDS_TO_IGNORE, entry),
577
+ relatedDocumentId: documentId,
578
+ locale: entry.locale,
579
+ status,
580
+ ...schemas
581
+ });
582
+ }
562
583
  });
563
584
  });
564
585
  return result;
@@ -1198,6 +1219,11 @@ const { createPolicy } = strapiUtils.policy;
1198
1219
  const hasPermissions = createPolicy({
1199
1220
  name: "plugin::content-manager.hasPermissions",
1200
1221
  validator: validateHasPermissionsInput,
1222
+ /**
1223
+ * NOTE: Action aliases are currently not checked at this level (policy).
1224
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1225
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1226
+ */
1201
1227
  handler(ctx, config = {}) {
1202
1228
  const { actions = [], hasAtLeastOne = false } = config;
1203
1229
  const { userAbility } = ctx.state;
@@ -1591,9 +1617,11 @@ const multipleLocaleSchema = strapiUtils.yup.lazy(
1591
1617
  (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1592
1618
  );
1593
1619
  const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1594
- const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1620
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1595
1621
  const { allowMultipleLocales } = opts;
1596
- const { locale, status, ...rest } = request || {};
1622
+ const { locale, status: providedStatus, ...rest } = request || {};
1623
+ const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1624
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1597
1625
  const schema = strapiUtils.yup.object().shape({
1598
1626
  locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1599
1627
  status: statusSchema
@@ -1641,7 +1669,7 @@ const createDocument = async (ctx, opts) => {
1641
1669
  const setCreator = strapiUtils.setCreatorFields({ user });
1642
1670
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1643
1671
  const sanitizedBody = await sanitizeFn(body);
1644
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1672
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1645
1673
  return documentManager2.create(model, {
1646
1674
  data: sanitizedBody,
1647
1675
  locale,
@@ -1660,7 +1688,7 @@ const updateDocument = async (ctx, opts) => {
1660
1688
  }
1661
1689
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1662
1690
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1663
- const { locale } = await getDocumentLocaleAndStatus(body);
1691
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1664
1692
  const [documentVersion, documentExists] = await Promise.all([
1665
1693
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1666
1694
  documentManager2.exists(model, id)
@@ -1698,7 +1726,7 @@ const collectionTypes = {
1698
1726
  }
1699
1727
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1700
1728
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1701
- const { locale, status } = await getDocumentLocaleAndStatus(query);
1729
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1702
1730
  const { results: documents, pagination } = await documentManager2.findPage(
1703
1731
  { ...permissionQuery, populate, locale, status },
1704
1732
  model
@@ -1733,7 +1761,7 @@ const collectionTypes = {
1733
1761
  }
1734
1762
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1735
1763
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1736
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1764
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1737
1765
  const version = await documentManager2.findOne(id, model, {
1738
1766
  populate,
1739
1767
  locale,
@@ -1800,7 +1828,7 @@ const collectionTypes = {
1800
1828
  }
1801
1829
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1802
1830
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1803
- const { locale } = await getDocumentLocaleAndStatus(body);
1831
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1804
1832
  const document = await documentManager2.findOne(id, model, {
1805
1833
  populate,
1806
1834
  locale,
@@ -1845,7 +1873,7 @@ const collectionTypes = {
1845
1873
  }
1846
1874
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1847
1875
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1848
- const { locale } = await getDocumentLocaleAndStatus(ctx.query);
1876
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1849
1877
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1850
1878
  if (documentLocales.length === 0) {
1851
1879
  return ctx.notFound();
@@ -1874,11 +1902,28 @@ const collectionTypes = {
1874
1902
  const publishedDocument = await strapi.db.transaction(async () => {
1875
1903
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1876
1904
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1877
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
1905
+ let document;
1906
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1907
+ const isCreate = fp.isNil(id);
1908
+ if (isCreate) {
1909
+ if (permissionChecker2.cannot.create()) {
1910
+ throw new strapiUtils.errors.ForbiddenError();
1911
+ }
1912
+ document = await createDocument(ctx, { populate });
1913
+ }
1914
+ const isUpdate = !isCreate;
1915
+ if (isUpdate) {
1916
+ document = await documentManager2.findOne(id, model, { populate, locale });
1917
+ if (!document) {
1918
+ throw new strapiUtils.errors.NotFoundError("Document not found");
1919
+ }
1920
+ if (permissionChecker2.can.update(document)) {
1921
+ await updateDocument(ctx);
1922
+ }
1923
+ }
1878
1924
  if (permissionChecker2.cannot.publish(document)) {
1879
1925
  throw new strapiUtils.errors.ForbiddenError();
1880
1926
  }
1881
- const { locale } = await getDocumentLocaleAndStatus(body);
1882
1927
  const publishResult = await documentManager2.publish(document.documentId, model, {
1883
1928
  locale
1884
1929
  // TODO: Allow setting creator fields on publish
@@ -1905,7 +1950,9 @@ const collectionTypes = {
1905
1950
  }
1906
1951
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1907
1952
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1908
- const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
1953
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
1954
+ allowMultipleLocales: true
1955
+ });
1909
1956
  const entityPromises = documentIds.map(
1910
1957
  (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1911
1958
  );
@@ -1932,7 +1979,7 @@ const collectionTypes = {
1932
1979
  if (permissionChecker2.cannot.unpublish()) {
1933
1980
  return ctx.forbidden();
1934
1981
  }
1935
- const { locale } = await getDocumentLocaleAndStatus(body);
1982
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1936
1983
  const entityPromises = documentIds.map(
1937
1984
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1938
1985
  );
@@ -1965,7 +2012,7 @@ const collectionTypes = {
1965
2012
  }
1966
2013
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1967
2014
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1968
- const { locale } = await getDocumentLocaleAndStatus(body);
2015
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1969
2016
  const document = await documentManager2.findOne(id, model, {
1970
2017
  populate,
1971
2018
  locale,
@@ -2002,7 +2049,7 @@ const collectionTypes = {
2002
2049
  }
2003
2050
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2004
2051
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2005
- const { locale } = await getDocumentLocaleAndStatus(body);
2052
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2006
2053
  const document = await documentManager2.findOne(id, model, {
2007
2054
  populate,
2008
2055
  locale,
@@ -2033,7 +2080,7 @@ const collectionTypes = {
2033
2080
  }
2034
2081
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2035
2082
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2036
- const { locale } = await getDocumentLocaleAndStatus(body);
2083
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2037
2084
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2038
2085
  populate,
2039
2086
  locale
@@ -2060,7 +2107,7 @@ const collectionTypes = {
2060
2107
  }
2061
2108
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2062
2109
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2063
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
2110
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2064
2111
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2065
2112
  if (!entity) {
2066
2113
  return ctx.notFound();
@@ -2083,7 +2130,7 @@ const collectionTypes = {
2083
2130
  if (permissionChecker2.cannot.read()) {
2084
2131
  return ctx.forbidden();
2085
2132
  }
2086
- const entities = await documentManager2.findMany(
2133
+ const documents = await documentManager2.findMany(
2087
2134
  {
2088
2135
  filters: {
2089
2136
  documentId: ids
@@ -2092,7 +2139,7 @@ const collectionTypes = {
2092
2139
  },
2093
2140
  model
2094
2141
  );
2095
- if (!entities) {
2142
+ if (!documents) {
2096
2143
  return ctx.notFound();
2097
2144
  }
2098
2145
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2283,20 +2330,13 @@ const sanitizeMainField = (model, mainField, userAbility) => {
2283
2330
  userAbility,
2284
2331
  model: model.uid
2285
2332
  });
2286
- if (!isListable(model, mainField)) {
2333
+ const isMainFieldListable = isListable(model, mainField);
2334
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2335
+ if (!isMainFieldListable || !canReadMainField) {
2287
2336
  return "id";
2288
2337
  }
2289
- if (permissionChecker2.cannot.read(null, mainField)) {
2290
- if (model.uid === "plugin::users-permissions.role") {
2291
- const userPermissionChecker = getService$1("permission-checker").create({
2292
- userAbility,
2293
- model: "plugin::users-permissions.user"
2294
- });
2295
- if (userPermissionChecker.can.read()) {
2296
- return "name";
2297
- }
2298
- }
2299
- return "id";
2338
+ if (model.uid === "plugin::users-permissions.role") {
2339
+ return "name";
2300
2340
  }
2301
2341
  return mainField;
2302
2342
  };
@@ -2554,9 +2594,7 @@ const relations = {
2554
2594
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2555
2595
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2556
2596
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2557
- ordering: "desc",
2558
- page: ctx.request.query.page,
2559
- pageSize: ctx.request.query.pageSize
2597
+ ordering: "desc"
2560
2598
  });
2561
2599
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2562
2600
  ctx.body = {
@@ -2588,7 +2626,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2588
2626
  throw new strapiUtils.errors.ForbiddenError();
2589
2627
  }
2590
2628
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2591
- const { locale } = await getDocumentLocaleAndStatus(body);
2629
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2592
2630
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2593
2631
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2594
2632
  // Find the first document to check if it exists
@@ -2629,7 +2667,7 @@ const singleTypes = {
2629
2667
  return ctx.forbidden();
2630
2668
  }
2631
2669
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2632
- const { locale, status } = await getDocumentLocaleAndStatus(query);
2670
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2633
2671
  const version = await findDocument(permissionQuery, model, { locale, status });
2634
2672
  if (!version) {
2635
2673
  if (permissionChecker2.cannot.create()) {
@@ -2674,7 +2712,7 @@ const singleTypes = {
2674
2712
  }
2675
2713
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2676
2714
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2677
- const { locale } = await getDocumentLocaleAndStatus(query);
2715
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2678
2716
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2679
2717
  populate,
2680
2718
  locale
@@ -2711,7 +2749,7 @@ const singleTypes = {
2711
2749
  if (permissionChecker2.cannot.publish(document)) {
2712
2750
  throw new strapiUtils.errors.ForbiddenError();
2713
2751
  }
2714
- const { locale } = await getDocumentLocaleAndStatus(document);
2752
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2715
2753
  const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2716
2754
  return publishResult.at(0);
2717
2755
  });
@@ -2734,7 +2772,7 @@ const singleTypes = {
2734
2772
  return ctx.forbidden();
2735
2773
  }
2736
2774
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2737
- const { locale } = await getDocumentLocaleAndStatus(body);
2775
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2738
2776
  const document = await findDocument(sanitizedQuery, model, { locale });
2739
2777
  if (!document) {
2740
2778
  return ctx.notFound();
@@ -2766,7 +2804,7 @@ const singleTypes = {
2766
2804
  return ctx.forbidden();
2767
2805
  }
2768
2806
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2769
- const { locale } = await getDocumentLocaleAndStatus(body);
2807
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2770
2808
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2771
2809
  if (!document) {
2772
2810
  return ctx.notFound();
@@ -2786,7 +2824,7 @@ const singleTypes = {
2786
2824
  const { query } = ctx.request;
2787
2825
  const documentManager2 = getService$1("document-manager");
2788
2826
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2789
- const { locale } = await getDocumentLocaleAndStatus(query);
2827
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2790
2828
  if (permissionChecker2.cannot.read()) {
2791
2829
  return ctx.forbidden();
2792
2830
  }
@@ -2807,7 +2845,7 @@ const uid$1 = {
2807
2845
  async generateUID(ctx) {
2808
2846
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2809
2847
  const { query = {} } = ctx.request;
2810
- const { locale } = await getDocumentLocaleAndStatus(query);
2848
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2811
2849
  await validateUIDField(contentTypeUID, field);
2812
2850
  const uidService = getService$1("uid");
2813
2851
  ctx.body = {
@@ -2819,7 +2857,7 @@ const uid$1 = {
2819
2857
  ctx.request.body
2820
2858
  );
2821
2859
  const { query = {} } = ctx.request;
2822
- const { locale } = await getDocumentLocaleAndStatus(query);
2860
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2823
2861
  await validateUIDField(contentTypeUID, field);
2824
2862
  const uidService = getService$1("uid");
2825
2863
  const isAvailable = await uidService.checkUIDAvailability({
@@ -3462,12 +3500,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3462
3500
  ability: userAbility,
3463
3501
  model
3464
3502
  });
3465
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3503
+ const { actionProvider } = strapi2.service("admin::permission");
3504
+ const toSubject = (entity) => {
3505
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3506
+ };
3466
3507
  const can = (action, entity, field) => {
3467
- return userAbility.can(action, toSubject(entity), field);
3508
+ const subject = toSubject(entity);
3509
+ const aliases = actionProvider.unstable_aliases(action, model);
3510
+ return (
3511
+ // Test the original action to see if it passes
3512
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3513
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3514
+ );
3468
3515
  };
3469
3516
  const cannot = (action, entity, field) => {
3470
- return userAbility.cannot(action, toSubject(entity), field);
3517
+ const subject = toSubject(entity);
3518
+ const aliases = actionProvider.unstable_aliases(action, model);
3519
+ return (
3520
+ // Test both the original action
3521
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3522
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3523
+ );
3471
3524
  };
3472
3525
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3473
3526
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3744,6 +3797,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3744
3797
  const attribute = model.attributes[attributeName];
3745
3798
  switch (attribute.type) {
3746
3799
  case "relation": {
3800
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
3801
+ if (isMorphRelation) {
3802
+ break;
3803
+ }
3747
3804
  if (isVisibleAttribute$1(model, attributeName)) {
3748
3805
  populateAcc[attributeName] = {
3749
3806
  count: true,
@@ -4121,7 +4178,13 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4121
4178
  */
4122
4179
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4123
4180
  if (!document) {
4124
- return document;
4181
+ return {
4182
+ data: document,
4183
+ meta: {
4184
+ availableLocales: [],
4185
+ availableStatus: []
4186
+ }
4187
+ };
4125
4188
  }
4126
4189
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4127
4190
  if (!hasDraftAndPublish) {
@@ -4229,10 +4292,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4229
4292
  async clone(id, body, uid2) {
4230
4293
  const populate = await buildDeepPopulate(uid2);
4231
4294
  const params = {
4232
- data: {
4233
- ...omitIdField(body),
4234
- [PUBLISHED_AT_ATTRIBUTE]: null
4235
- },
4295
+ data: omitIdField(body),
4236
4296
  populate
4237
4297
  };
4238
4298
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));