@strapi/content-manager 5.0.0-beta.7 → 5.0.0-beta.8

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 (143) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-uTMkLI60.mjs → ComponentConfigurationPage-CuWgXugY.mjs} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-uTMkLI60.mjs.map → ComponentConfigurationPage-CuWgXugY.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-DMq0wvcL.js → ComponentConfigurationPage-by0e_kNd.js} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-DMq0wvcL.js.map → ComponentConfigurationPage-by0e_kNd.js.map} +1 -1
  5. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  6. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  7. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  8. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  9. package/dist/_chunks/{EditConfigurationPage-BFpQwwbc.js → EditConfigurationPage-CqBeCPGH.js} +3 -3
  10. package/dist/_chunks/{EditConfigurationPage-BFpQwwbc.js.map → EditConfigurationPage-CqBeCPGH.js.map} +1 -1
  11. package/dist/_chunks/{EditConfigurationPage-B2HhCh-b.mjs → EditConfigurationPage-DbI4KMyz.mjs} +3 -3
  12. package/dist/_chunks/{EditConfigurationPage-B2HhCh-b.mjs.map → EditConfigurationPage-DbI4KMyz.mjs.map} +1 -1
  13. package/dist/_chunks/{EditViewPage-CXXue16T.js → EditViewPage-ChgloMyO.js} +5 -5
  14. package/dist/_chunks/{EditViewPage-CXXue16T.js.map → EditViewPage-ChgloMyO.js.map} +1 -1
  15. package/dist/_chunks/{EditViewPage-BVIrgjyG.mjs → EditViewPage-dFPBya9U.mjs} +5 -5
  16. package/dist/_chunks/{EditViewPage-BVIrgjyG.mjs.map → EditViewPage-dFPBya9U.mjs.map} +1 -1
  17. package/dist/_chunks/{Field-0_2h1vuK.mjs → Field-C1nUKcdS.mjs} +240 -357
  18. package/dist/_chunks/Field-C1nUKcdS.mjs.map +1 -0
  19. package/dist/_chunks/{Field-ZgzKlgxR.js → Field-dLk-vgLL.js} +240 -357
  20. package/dist/_chunks/Field-dLk-vgLL.js.map +1 -0
  21. package/dist/_chunks/{Form-DgTc2qkx.js → Form-CbXtmHC_.js} +9 -6
  22. package/dist/_chunks/Form-CbXtmHC_.js.map +1 -0
  23. package/dist/_chunks/{Form-B7TUnQDd.mjs → Form-DOlpi7Js.mjs} +9 -6
  24. package/dist/_chunks/Form-DOlpi7Js.mjs.map +1 -0
  25. package/dist/_chunks/{History-Dug_4HIA.mjs → History-BFNUAiGc.mjs} +8 -8
  26. package/dist/_chunks/{History-Dug_4HIA.mjs.map → History-BFNUAiGc.mjs.map} +1 -1
  27. package/dist/_chunks/{History-DtHjQuqM.js → History-BjDfohBr.js} +8 -8
  28. package/dist/_chunks/{History-DtHjQuqM.js.map → History-BjDfohBr.js.map} +1 -1
  29. package/dist/_chunks/{ListConfigurationPage-CmEeNg6T.mjs → ListConfigurationPage-DDi0KqFm.mjs} +2 -2
  30. package/dist/_chunks/{ListConfigurationPage-CmEeNg6T.mjs.map → ListConfigurationPage-DDi0KqFm.mjs.map} +1 -1
  31. package/dist/_chunks/{ListConfigurationPage-BuSdTjfa.js → ListConfigurationPage-IQBgWTaa.js} +2 -2
  32. package/dist/_chunks/{ListConfigurationPage-BuSdTjfa.js.map → ListConfigurationPage-IQBgWTaa.js.map} +1 -1
  33. package/dist/_chunks/{ListViewPage-Dsoa3wEA.mjs → ListViewPage-BPjljUsH.mjs} +8 -16
  34. package/dist/_chunks/ListViewPage-BPjljUsH.mjs.map +1 -0
  35. package/dist/_chunks/{ListViewPage-CExWwa4S.js → ListViewPage-CZYGqlvF.js} +11 -18
  36. package/dist/_chunks/ListViewPage-CZYGqlvF.js.map +1 -0
  37. package/dist/_chunks/{NoContentTypePage-DCUL8gVi.js → NoContentTypePage-BOAI6VZ1.js} +2 -2
  38. package/dist/_chunks/{NoContentTypePage-DCUL8gVi.js.map → NoContentTypePage-BOAI6VZ1.js.map} +1 -1
  39. package/dist/_chunks/{NoContentTypePage-Dh38hBXB.mjs → NoContentTypePage-DaWw67K-.mjs} +2 -2
  40. package/dist/_chunks/{NoContentTypePage-Dh38hBXB.mjs.map → NoContentTypePage-DaWw67K-.mjs.map} +1 -1
  41. package/dist/_chunks/{NoPermissionsPage-Dt2O40ey.mjs → NoPermissionsPage-CZrJH00p.mjs} +2 -2
  42. package/dist/_chunks/{NoPermissionsPage-Dt2O40ey.mjs.map → NoPermissionsPage-CZrJH00p.mjs.map} +1 -1
  43. package/dist/_chunks/{NoPermissionsPage-BK-XCpIy.js → NoPermissionsPage-cYEtLc_e.js} +2 -2
  44. package/dist/_chunks/{NoPermissionsPage-BK-XCpIy.js.map → NoPermissionsPage-cYEtLc_e.js.map} +1 -1
  45. package/dist/_chunks/{Relations-DZyjWZHl.mjs → Relations-DTowyge2.mjs} +7 -5
  46. package/dist/_chunks/{Relations-DZyjWZHl.mjs.map → Relations-DTowyge2.mjs.map} +1 -1
  47. package/dist/_chunks/{Relations-CNypkp-g.js → Relations-DU6B7irU.js} +7 -5
  48. package/dist/_chunks/{Relations-CNypkp-g.js.map → Relations-DU6B7irU.js.map} +1 -1
  49. package/dist/_chunks/{en-C-V1_90f.js → en-DTULi5-d.js} +3 -1
  50. package/dist/_chunks/{en-C-V1_90f.js.map → en-DTULi5-d.js.map} +1 -1
  51. package/dist/_chunks/{en-MBPul9Su.mjs → en-GCOTL6jR.mjs} +3 -1
  52. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-GCOTL6jR.mjs.map} +1 -1
  53. package/dist/_chunks/{index-B3c-4it4.mjs → index-BaGHmIir.mjs} +488 -196
  54. package/dist/_chunks/index-BaGHmIir.mjs.map +1 -0
  55. package/dist/_chunks/{index-DFK7LwDW.js → index-CCJeB7Rw.js} +480 -188
  56. package/dist/_chunks/index-CCJeB7Rw.js.map +1 -0
  57. package/dist/_chunks/{layout-B5cm7cZj.mjs → layout-BinjszSQ.mjs} +6 -6
  58. package/dist/_chunks/layout-BinjszSQ.mjs.map +1 -0
  59. package/dist/_chunks/{layout-DLih5-_W.js → layout-ni_L9kT1.js} +6 -6
  60. package/dist/_chunks/layout-ni_L9kT1.js.map +1 -0
  61. package/dist/_chunks/{relations-CTvkuINQ.js → relations-CeJAJc5I.js} +2 -2
  62. package/dist/_chunks/{relations-CTvkuINQ.js.map → relations-CeJAJc5I.js.map} +1 -1
  63. package/dist/_chunks/{relations-BZkrMa2z.mjs → relations-c91ji5eR.mjs} +2 -2
  64. package/dist/_chunks/{relations-BZkrMa2z.mjs.map → relations-c91ji5eR.mjs.map} +1 -1
  65. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  66. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  67. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  68. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  69. package/dist/admin/index.js +2 -1
  70. package/dist/admin/index.js.map +1 -1
  71. package/dist/admin/index.mjs +5 -4
  72. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  73. package/dist/admin/src/content-manager.d.ts +3 -3
  74. package/dist/admin/src/exports.d.ts +1 -0
  75. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  76. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  77. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  78. package/dist/admin/src/hooks/useDocumentLayout.d.ts +1 -1
  79. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +3 -1
  80. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  81. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  82. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  83. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  84. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +2 -15
  85. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  86. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  87. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +56 -35
  88. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  89. package/dist/admin/src/services/api.d.ts +2 -3
  90. package/dist/admin/src/services/components.d.ts +2 -2
  91. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  92. package/dist/admin/src/services/documents.d.ts +29 -17
  93. package/dist/admin/src/services/init.d.ts +2 -2
  94. package/dist/admin/src/services/relations.d.ts +3 -3
  95. package/dist/admin/src/services/uid.d.ts +3 -3
  96. package/dist/admin/src/utils/api.d.ts +4 -17
  97. package/dist/admin/src/utils/validation.d.ts +1 -6
  98. package/dist/server/index.js +232 -116
  99. package/dist/server/index.js.map +1 -1
  100. package/dist/server/index.mjs +234 -118
  101. package/dist/server/index.mjs.map +1 -1
  102. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  103. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  104. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  105. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  106. package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
  107. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  108. package/dist/server/src/history/services/history.d.ts.map +1 -1
  109. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  110. package/dist/server/src/index.d.ts +12 -33
  111. package/dist/server/src/index.d.ts.map +1 -1
  112. package/dist/server/src/services/document-manager.d.ts +6 -6
  113. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  114. package/dist/server/src/services/document-metadata.d.ts +8 -29
  115. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  116. package/dist/server/src/services/index.d.ts +12 -33
  117. package/dist/server/src/services/index.d.ts.map +1 -1
  118. package/dist/server/src/services/utils/populate.d.ts +8 -1
  119. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  120. package/dist/shared/contracts/collection-types.d.ts +11 -5
  121. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  122. package/dist/shared/contracts/relations.d.ts +2 -2
  123. package/dist/shared/contracts/relations.d.ts.map +1 -1
  124. package/package.json +11 -11
  125. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  126. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  127. package/dist/_chunks/Field-0_2h1vuK.mjs.map +0 -1
  128. package/dist/_chunks/Field-ZgzKlgxR.js.map +0 -1
  129. package/dist/_chunks/Form-B7TUnQDd.mjs.map +0 -1
  130. package/dist/_chunks/Form-DgTc2qkx.js.map +0 -1
  131. package/dist/_chunks/ListViewPage-CExWwa4S.js.map +0 -1
  132. package/dist/_chunks/ListViewPage-Dsoa3wEA.mjs.map +0 -1
  133. package/dist/_chunks/index-B3c-4it4.mjs.map +0 -1
  134. package/dist/_chunks/index-DFK7LwDW.js.map +0 -1
  135. package/dist/_chunks/layout-B5cm7cZj.mjs.map +0 -1
  136. package/dist/_chunks/layout-DLih5-_W.js.map +0 -1
  137. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  138. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  139. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  140. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  141. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +0 -31
  142. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  143. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -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, pagination } from "@strapi/utils";
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, castArray } from "lodash/fp";
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, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, isNil as isNil$1, getOr, propEq, merge, groupBy, castArray } from "lodash/fp";
3
3
  import "@strapi/types";
4
4
  import * as yup from "yup";
5
5
  import { scheduleJob } from "node-schedule";
@@ -492,6 +492,12 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
492
492
  const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
493
493
  const defaultLocale = await serviceUtils.getDefaultLocale();
494
494
  const locale = documentContext.locale || defaultLocale;
495
+ if (Array.isArray(locale)) {
496
+ strapi2.log.warn(
497
+ "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
498
+ );
499
+ return next();
500
+ }
495
501
  const document = await strapi2.documents(contentTypeUid).findOne({
496
502
  documentId: documentContext.documentId,
497
503
  locale,
@@ -1551,15 +1557,47 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1551
1557
  }
1552
1558
  }, body);
1553
1559
  };
1554
- const getDocumentLocaleAndStatus = (request) => {
1560
+ const singleLocaleSchema = yup$1.string().nullable();
1561
+ const multipleLocaleSchema = yup$1.lazy(
1562
+ (value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1563
+ );
1564
+ const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
1565
+ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1566
+ const { allowMultipleLocales } = opts;
1555
1567
  const { locale, status, ...rest } = request || {};
1556
- if (!isNil$1(locale) && typeof locale !== "string") {
1557
- throw new errors.ValidationError(`Invalid locale: ${locale}`);
1558
- }
1559
- if (!isNil$1(status) && !["draft", "published"].includes(status)) {
1560
- throw new errors.ValidationError(`Invalid status: ${status}`);
1568
+ const schema = yup$1.object().shape({
1569
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1570
+ status: statusSchema
1571
+ });
1572
+ try {
1573
+ await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1574
+ return { locale, status, ...rest };
1575
+ } catch (error) {
1576
+ throw new errors.ValidationError(`Validation error: ${error.message}`);
1561
1577
  }
1562
- return { locale, status, ...rest };
1578
+ };
1579
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1580
+ const documentMetadata2 = getService$1("document-metadata");
1581
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1582
+ let {
1583
+ meta: { availableLocales, availableStatus }
1584
+ } = serviceOutput;
1585
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1586
+ availableLocales = await async.map(
1587
+ availableLocales,
1588
+ async (localeDocument) => metadataSanitizer(localeDocument)
1589
+ );
1590
+ availableStatus = await async.map(
1591
+ availableStatus,
1592
+ async (statusDocument) => metadataSanitizer(statusDocument)
1593
+ );
1594
+ return {
1595
+ ...serviceOutput,
1596
+ meta: {
1597
+ availableLocales,
1598
+ availableStatus
1599
+ }
1600
+ };
1563
1601
  };
1564
1602
  const createDocument = async (ctx, opts) => {
1565
1603
  const { userAbility, user } = ctx.state;
@@ -1574,7 +1612,7 @@ const createDocument = async (ctx, opts) => {
1574
1612
  const setCreator = setCreatorFields({ user });
1575
1613
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1576
1614
  const sanitizedBody = await sanitizeFn(body);
1577
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1615
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1578
1616
  return documentManager2.create(model, {
1579
1617
  data: sanitizedBody,
1580
1618
  locale,
@@ -1593,7 +1631,7 @@ const updateDocument = async (ctx, opts) => {
1593
1631
  }
1594
1632
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1595
1633
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1596
- const { locale } = getDocumentLocaleAndStatus(body);
1634
+ const { locale } = await getDocumentLocaleAndStatus(body);
1597
1635
  const [documentVersion, documentExists] = await Promise.all([
1598
1636
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1599
1637
  documentManager2.exists(model, id)
@@ -1631,7 +1669,7 @@ const collectionTypes = {
1631
1669
  }
1632
1670
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1633
1671
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1634
- const { locale, status } = getDocumentLocaleAndStatus(query);
1672
+ const { locale, status } = await getDocumentLocaleAndStatus(query);
1635
1673
  const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
1636
1674
  { ...permissionQuery, populate, locale, status },
1637
1675
  model
@@ -1660,14 +1698,13 @@ const collectionTypes = {
1660
1698
  const { userAbility } = ctx.state;
1661
1699
  const { model, id } = ctx.params;
1662
1700
  const documentManager2 = getService$1("document-manager");
1663
- const documentMetadata2 = getService$1("document-metadata");
1664
1701
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1665
1702
  if (permissionChecker2.cannot.read()) {
1666
1703
  return ctx.forbidden();
1667
1704
  }
1668
1705
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1669
1706
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1670
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
1707
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1671
1708
  const version = await documentManager2.findOne(id, model, {
1672
1709
  populate,
1673
1710
  locale,
@@ -1678,8 +1715,10 @@ const collectionTypes = {
1678
1715
  if (!exists) {
1679
1716
  return ctx.notFound();
1680
1717
  }
1681
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
1718
+ const { meta } = await formatDocumentWithMetadata(
1719
+ permissionChecker2,
1682
1720
  model,
1721
+ // @ts-expect-error TODO: fix
1683
1722
  { id, locale, publishedAt: null },
1684
1723
  { availableLocales: true, availableStatus: false }
1685
1724
  );
@@ -1690,12 +1729,11 @@ const collectionTypes = {
1690
1729
  return ctx.forbidden();
1691
1730
  }
1692
1731
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1693
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1732
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1694
1733
  },
1695
1734
  async create(ctx) {
1696
1735
  const { userAbility } = ctx.state;
1697
1736
  const { model } = ctx.params;
1698
- const documentMetadata2 = getService$1("document-metadata");
1699
1737
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1700
1738
  const [totalEntries, document] = await Promise.all([
1701
1739
  strapi.db.query(model).count(),
@@ -1703,7 +1741,7 @@ const collectionTypes = {
1703
1741
  ]);
1704
1742
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1705
1743
  ctx.status = 201;
1706
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1744
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1707
1745
  // Empty metadata as it's not relevant for a new document
1708
1746
  availableLocales: false,
1709
1747
  availableStatus: false
@@ -1717,25 +1755,23 @@ const collectionTypes = {
1717
1755
  async update(ctx) {
1718
1756
  const { userAbility } = ctx.state;
1719
1757
  const { model } = ctx.params;
1720
- const documentMetadata2 = getService$1("document-metadata");
1721
1758
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1722
1759
  const updatedVersion = await updateDocument(ctx);
1723
1760
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1724
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
1761
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1725
1762
  },
1726
1763
  async clone(ctx) {
1727
1764
  const { userAbility, user } = ctx.state;
1728
1765
  const { model, sourceId: id } = ctx.params;
1729
1766
  const { body } = ctx.request;
1730
1767
  const documentManager2 = getService$1("document-manager");
1731
- const documentMetadata2 = getService$1("document-metadata");
1732
1768
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1733
1769
  if (permissionChecker2.cannot.create()) {
1734
1770
  return ctx.forbidden();
1735
1771
  }
1736
1772
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1737
1773
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1738
- const { locale } = getDocumentLocaleAndStatus(body);
1774
+ const { locale } = await getDocumentLocaleAndStatus(body);
1739
1775
  const document = await documentManager2.findOne(id, model, {
1740
1776
  populate,
1741
1777
  locale,
@@ -1751,7 +1787,7 @@ const collectionTypes = {
1751
1787
  const sanitizedBody = await sanitizeFn(body);
1752
1788
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1753
1789
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1754
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1790
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1755
1791
  // Empty metadata as it's not relevant for a new document
1756
1792
  availableLocales: false,
1757
1793
  availableStatus: false
@@ -1780,7 +1816,7 @@ const collectionTypes = {
1780
1816
  }
1781
1817
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1782
1818
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1783
- const { locale } = getDocumentLocaleAndStatus(ctx.query);
1819
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query);
1784
1820
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1785
1821
  if (documentLocales.length === 0) {
1786
1822
  return ctx.notFound();
@@ -1802,7 +1838,6 @@ const collectionTypes = {
1802
1838
  const { id, model } = ctx.params;
1803
1839
  const { body } = ctx.request;
1804
1840
  const documentManager2 = getService$1("document-manager");
1805
- const documentMetadata2 = getService$1("document-metadata");
1806
1841
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1807
1842
  if (permissionChecker2.cannot.publish()) {
1808
1843
  return ctx.forbidden();
@@ -1814,15 +1849,19 @@ const collectionTypes = {
1814
1849
  if (permissionChecker2.cannot.publish(document)) {
1815
1850
  throw new errors.ForbiddenError();
1816
1851
  }
1817
- const { locale } = getDocumentLocaleAndStatus(body);
1818
- return documentManager2.publish(document.documentId, model, {
1852
+ const { locale } = await getDocumentLocaleAndStatus(body);
1853
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1819
1854
  locale
1820
1855
  // TODO: Allow setting creator fields on publish
1821
1856
  // data: setCreatorFields({ user, isEdition: true })({}),
1822
1857
  });
1858
+ if (!publishResult || publishResult.length === 0) {
1859
+ throw new errors.NotFoundError("Document not found or already published.");
1860
+ }
1861
+ return publishResult[0];
1823
1862
  });
1824
1863
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1825
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1864
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1826
1865
  },
1827
1866
  async bulkPublish(ctx) {
1828
1867
  const { userAbility } = ctx.state;
@@ -1835,9 +1874,11 @@ const collectionTypes = {
1835
1874
  if (permissionChecker2.cannot.publish()) {
1836
1875
  return ctx.forbidden();
1837
1876
  }
1838
- const { locale } = getDocumentLocaleAndStatus(body);
1877
+ const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1878
+ const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1879
+ const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
1839
1880
  const entityPromises = documentIds.map(
1840
- (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: false })
1881
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1841
1882
  );
1842
1883
  const entities = (await Promise.all(entityPromises)).flat();
1843
1884
  for (const entity of entities) {
@@ -1848,8 +1889,7 @@ const collectionTypes = {
1848
1889
  return ctx.forbidden();
1849
1890
  }
1850
1891
  }
1851
- const entitiesIds = entities.map((document) => document.documentId);
1852
- const { count } = await documentManager2.publishMany(entitiesIds, model, { locale });
1892
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1853
1893
  ctx.body = { count };
1854
1894
  },
1855
1895
  async bulkUnpublish(ctx) {
@@ -1863,7 +1903,7 @@ const collectionTypes = {
1863
1903
  if (permissionChecker2.cannot.unpublish()) {
1864
1904
  return ctx.forbidden();
1865
1905
  }
1866
- const { locale } = getDocumentLocaleAndStatus(body);
1906
+ const { locale } = await getDocumentLocaleAndStatus(body);
1867
1907
  const entityPromises = documentIds.map(
1868
1908
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1869
1909
  );
@@ -1887,7 +1927,6 @@ const collectionTypes = {
1887
1927
  body: { discardDraft, ...body }
1888
1928
  } = ctx.request;
1889
1929
  const documentManager2 = getService$1("document-manager");
1890
- const documentMetadata2 = getService$1("document-metadata");
1891
1930
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1892
1931
  if (permissionChecker2.cannot.unpublish()) {
1893
1932
  return ctx.forbidden();
@@ -1897,7 +1936,7 @@ const collectionTypes = {
1897
1936
  }
1898
1937
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1899
1938
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1900
- const { locale } = getDocumentLocaleAndStatus(body);
1939
+ const { locale } = await getDocumentLocaleAndStatus(body);
1901
1940
  const document = await documentManager2.findOne(id, model, {
1902
1941
  populate,
1903
1942
  locale,
@@ -1919,7 +1958,7 @@ const collectionTypes = {
1919
1958
  ctx.body = await async.pipe(
1920
1959
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1921
1960
  permissionChecker2.sanitizeOutput,
1922
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
1961
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1923
1962
  )(document);
1924
1963
  });
1925
1964
  },
@@ -1928,14 +1967,13 @@ const collectionTypes = {
1928
1967
  const { id, model } = ctx.params;
1929
1968
  const { body } = ctx.request;
1930
1969
  const documentManager2 = getService$1("document-manager");
1931
- const documentMetadata2 = getService$1("document-metadata");
1932
1970
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1933
1971
  if (permissionChecker2.cannot.discard()) {
1934
1972
  return ctx.forbidden();
1935
1973
  }
1936
1974
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1937
1975
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1938
- const { locale } = getDocumentLocaleAndStatus(body);
1976
+ const { locale } = await getDocumentLocaleAndStatus(body);
1939
1977
  const document = await documentManager2.findOne(id, model, {
1940
1978
  populate,
1941
1979
  locale,
@@ -1950,7 +1988,7 @@ const collectionTypes = {
1950
1988
  ctx.body = await async.pipe(
1951
1989
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1952
1990
  permissionChecker2.sanitizeOutput,
1953
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
1991
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1954
1992
  )(document);
1955
1993
  },
1956
1994
  async bulkDelete(ctx) {
@@ -1966,7 +2004,7 @@ const collectionTypes = {
1966
2004
  }
1967
2005
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
1968
2006
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1969
- const { locale } = getDocumentLocaleAndStatus(body);
2007
+ const { locale } = await getDocumentLocaleAndStatus(body);
1970
2008
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
1971
2009
  populate,
1972
2010
  locale
@@ -1993,7 +2031,7 @@ const collectionTypes = {
1993
2031
  }
1994
2032
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1995
2033
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1996
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
2034
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1997
2035
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
1998
2036
  if (!entity) {
1999
2037
  return ctx.notFound();
@@ -2008,26 +2046,27 @@ const collectionTypes = {
2008
2046
  },
2009
2047
  async countManyEntriesDraftRelations(ctx) {
2010
2048
  const { userAbility } = ctx.state;
2011
- const { documentIds, locale } = ctx.request.query;
2049
+ const ids = ctx.request.query.documentIds;
2050
+ const locale = ctx.request.query.locale;
2012
2051
  const { model } = ctx.params;
2013
2052
  const documentManager2 = getService$1("document-manager");
2014
2053
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2015
2054
  if (permissionChecker2.cannot.read()) {
2016
2055
  return ctx.forbidden();
2017
2056
  }
2018
- const documents = await documentManager2.findMany(
2057
+ const entities = await documentManager2.findMany(
2019
2058
  {
2020
2059
  filters: {
2021
- documentId: { $in: documentIds }
2060
+ documentId: ids
2022
2061
  },
2023
2062
  locale
2024
2063
  },
2025
2064
  model
2026
2065
  );
2027
- if (!documents) {
2066
+ if (!entities) {
2028
2067
  return ctx.notFound();
2029
2068
  }
2030
- const number = await documentManager2.countManyEntriesDraftRelations(documentIds, model, locale);
2069
+ const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
2031
2070
  return {
2032
2071
  data: number
2033
2072
  };
@@ -2520,7 +2559,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2520
2559
  throw new errors.ForbiddenError();
2521
2560
  }
2522
2561
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2523
- const { locale } = getDocumentLocaleAndStatus(body);
2562
+ const { locale } = await getDocumentLocaleAndStatus(body);
2524
2563
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2525
2564
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2526
2565
  // Find the first document to check if it exists
@@ -2557,12 +2596,11 @@ const singleTypes = {
2557
2596
  const { model } = ctx.params;
2558
2597
  const { query = {} } = ctx.request;
2559
2598
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2560
- const documentMetadata2 = getService$1("document-metadata");
2561
2599
  if (permissionChecker2.cannot.read()) {
2562
2600
  return ctx.forbidden();
2563
2601
  }
2564
2602
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2565
- const { locale, status } = getDocumentLocaleAndStatus(query);
2603
+ const { locale, status } = await getDocumentLocaleAndStatus(query);
2566
2604
  const version = await findDocument(permissionQuery, model, { locale, status });
2567
2605
  if (!version) {
2568
2606
  if (permissionChecker2.cannot.create()) {
@@ -2572,8 +2610,10 @@ const singleTypes = {
2572
2610
  if (!document) {
2573
2611
  return ctx.notFound();
2574
2612
  }
2575
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2613
+ const { meta } = await formatDocumentWithMetadata(
2614
+ permissionChecker2,
2576
2615
  model,
2616
+ // @ts-expect-error - fix types
2577
2617
  { id: document.documentId, locale, publishedAt: null },
2578
2618
  { availableLocales: true, availableStatus: false }
2579
2619
  );
@@ -2584,16 +2624,15 @@ const singleTypes = {
2584
2624
  return ctx.forbidden();
2585
2625
  }
2586
2626
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2587
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2627
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2588
2628
  },
2589
2629
  async createOrUpdate(ctx) {
2590
2630
  const { userAbility } = ctx.state;
2591
2631
  const { model } = ctx.params;
2592
- const documentMetadata2 = getService$1("document-metadata");
2593
2632
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2594
2633
  const document = await createOrUpdateDocument(ctx);
2595
2634
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2596
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2635
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2597
2636
  },
2598
2637
  async delete(ctx) {
2599
2638
  const { userAbility } = ctx.state;
@@ -2606,7 +2645,7 @@ const singleTypes = {
2606
2645
  }
2607
2646
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2608
2647
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2609
- const { locale } = getDocumentLocaleAndStatus(query);
2648
+ const { locale } = await getDocumentLocaleAndStatus(query);
2610
2649
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2611
2650
  populate,
2612
2651
  locale
@@ -2629,7 +2668,6 @@ const singleTypes = {
2629
2668
  const { model } = ctx.params;
2630
2669
  const { query = {} } = ctx.request;
2631
2670
  const documentManager2 = getService$1("document-manager");
2632
- const documentMetadata2 = getService$1("document-metadata");
2633
2671
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2634
2672
  if (permissionChecker2.cannot.publish()) {
2635
2673
  return ctx.forbidden();
@@ -2644,11 +2682,12 @@ const singleTypes = {
2644
2682
  if (permissionChecker2.cannot.publish(document)) {
2645
2683
  throw new errors.ForbiddenError();
2646
2684
  }
2647
- const { locale } = getDocumentLocaleAndStatus(document);
2648
- return documentManager2.publish(document.documentId, model, { locale });
2685
+ const { locale } = await getDocumentLocaleAndStatus(document);
2686
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2687
+ return publishResult.at(0);
2649
2688
  });
2650
2689
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2651
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2690
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2652
2691
  },
2653
2692
  async unpublish(ctx) {
2654
2693
  const { userAbility } = ctx.state;
@@ -2658,7 +2697,6 @@ const singleTypes = {
2658
2697
  query = {}
2659
2698
  } = ctx.request;
2660
2699
  const documentManager2 = getService$1("document-manager");
2661
- const documentMetadata2 = getService$1("document-metadata");
2662
2700
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2663
2701
  if (permissionChecker2.cannot.unpublish()) {
2664
2702
  return ctx.forbidden();
@@ -2667,7 +2705,7 @@ const singleTypes = {
2667
2705
  return ctx.forbidden();
2668
2706
  }
2669
2707
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2670
- const { locale } = getDocumentLocaleAndStatus(body);
2708
+ const { locale } = await getDocumentLocaleAndStatus(body);
2671
2709
  const document = await findDocument(sanitizedQuery, model, { locale });
2672
2710
  if (!document) {
2673
2711
  return ctx.notFound();
@@ -2685,7 +2723,7 @@ const singleTypes = {
2685
2723
  ctx.body = await async.pipe(
2686
2724
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2687
2725
  permissionChecker2.sanitizeOutput,
2688
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2726
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2689
2727
  )(document);
2690
2728
  });
2691
2729
  },
@@ -2694,13 +2732,12 @@ const singleTypes = {
2694
2732
  const { model } = ctx.params;
2695
2733
  const { body, query = {} } = ctx.request;
2696
2734
  const documentManager2 = getService$1("document-manager");
2697
- const documentMetadata2 = getService$1("document-metadata");
2698
2735
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2699
2736
  if (permissionChecker2.cannot.discard()) {
2700
2737
  return ctx.forbidden();
2701
2738
  }
2702
2739
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2703
- const { locale } = getDocumentLocaleAndStatus(body);
2740
+ const { locale } = await getDocumentLocaleAndStatus(body);
2704
2741
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2705
2742
  if (!document) {
2706
2743
  return ctx.notFound();
@@ -2711,7 +2748,7 @@ const singleTypes = {
2711
2748
  ctx.body = await async.pipe(
2712
2749
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2713
2750
  permissionChecker2.sanitizeOutput,
2714
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2751
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2715
2752
  )(document);
2716
2753
  },
2717
2754
  async countDraftRelations(ctx) {
@@ -2720,7 +2757,7 @@ const singleTypes = {
2720
2757
  const { query } = ctx.request;
2721
2758
  const documentManager2 = getService$1("document-manager");
2722
2759
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2723
- const { locale } = getDocumentLocaleAndStatus(query);
2760
+ const { locale } = await getDocumentLocaleAndStatus(query);
2724
2761
  if (permissionChecker2.cannot.read()) {
2725
2762
  return ctx.forbidden();
2726
2763
  }
@@ -2741,7 +2778,7 @@ const uid$1 = {
2741
2778
  async generateUID(ctx) {
2742
2779
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2743
2780
  const { query = {} } = ctx.request;
2744
- const { locale } = getDocumentLocaleAndStatus(query);
2781
+ const { locale } = await getDocumentLocaleAndStatus(query);
2745
2782
  await validateUIDField(contentTypeUID, field);
2746
2783
  const uidService = getService$1("uid");
2747
2784
  ctx.body = {
@@ -2753,7 +2790,7 @@ const uid$1 = {
2753
2790
  ctx.request.body
2754
2791
  );
2755
2792
  const { query = {} } = ctx.request;
2756
- const { locale } = getDocumentLocaleAndStatus(query);
2793
+ const { locale } = await getDocumentLocaleAndStatus(query);
2757
2794
  await validateUIDField(contentTypeUID, field);
2758
2795
  const uidService = getService$1("uid");
2759
2796
  const isAvailable = await uidService.checkUIDAvailability({
@@ -3544,7 +3581,7 @@ const permission = ({ strapi: strapi2 }) => ({
3544
3581
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3545
3582
  }
3546
3583
  });
3547
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
3584
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
3548
3585
  const { isAnyToMany } = strapiUtils.relations;
3549
3586
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
3550
3587
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3635,6 +3672,42 @@ const getDeepPopulate = (uid2, {
3635
3672
  {}
3636
3673
  );
3637
3674
  };
3675
+ const getValidatableFieldsPopulate = (uid2, {
3676
+ initialPopulate = {},
3677
+ countMany = false,
3678
+ countOne = false,
3679
+ maxLevel = Infinity
3680
+ } = {}, level = 1) => {
3681
+ if (level > maxLevel) {
3682
+ return {};
3683
+ }
3684
+ const model = strapi.getModel(uid2);
3685
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3686
+ if (!getDoesAttributeRequireValidation(attribute)) {
3687
+ return populateAcc;
3688
+ }
3689
+ if (isScalarAttribute(attribute)) {
3690
+ return merge(populateAcc, {
3691
+ [attributeName]: true
3692
+ });
3693
+ }
3694
+ return merge(
3695
+ populateAcc,
3696
+ getPopulateFor(
3697
+ attributeName,
3698
+ model,
3699
+ {
3700
+ // @ts-expect-error - improve types
3701
+ initialPopulate: initialPopulate?.[attributeName],
3702
+ countMany,
3703
+ countOne,
3704
+ maxLevel
3705
+ },
3706
+ level
3707
+ )
3708
+ );
3709
+ }, {});
3710
+ };
3638
3711
  const getDeepPopulateDraftCount = (uid2) => {
3639
3712
  const model = strapi.getModel(uid2);
3640
3713
  let hasRelations = false;
@@ -3863,41 +3936,70 @@ const AVAILABLE_STATUS_FIELDS = [
3863
3936
  "updatedBy",
3864
3937
  "status"
3865
3938
  ];
3866
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
3939
+ const AVAILABLE_LOCALES_FIELDS = [
3940
+ "id",
3941
+ "locale",
3942
+ "updatedAt",
3943
+ "createdAt",
3944
+ "status",
3945
+ "publishedAt",
3946
+ "documentId"
3947
+ ];
3867
3948
  const CONTENT_MANAGER_STATUS = {
3868
3949
  PUBLISHED: "published",
3869
3950
  DRAFT: "draft",
3870
3951
  MODIFIED: "modified"
3871
3952
  };
3872
- const areDatesEqual = (date1, date2, threshold) => {
3873
- if (!date1 || !date2) {
3953
+ const getIsVersionLatestModification = (version, otherVersion) => {
3954
+ if (!version || !version.updatedAt) {
3874
3955
  return false;
3875
3956
  }
3876
- const time1 = new Date(date1).getTime();
3877
- const time2 = new Date(date2).getTime();
3878
- const difference2 = Math.abs(time1 - time2);
3879
- return difference2 <= threshold;
3957
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
3958
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
3959
+ return versionUpdatedAt > otherUpdatedAt;
3880
3960
  };
3881
3961
  const documentMetadata = ({ strapi: strapi2 }) => ({
3882
3962
  /**
3883
3963
  * Returns available locales of a document for the current status
3884
3964
  */
3885
- getAvailableLocales(uid2, version, allVersions) {
3965
+ async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
3886
3966
  const versionsByLocale = groupBy("locale", allVersions);
3887
3967
  delete versionsByLocale[version.locale];
3888
- return Object.values(versionsByLocale).map((localeVersions) => {
3889
- if (!contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2))) {
3890
- return pick(AVAILABLE_LOCALES_FIELDS, localeVersions[0]);
3968
+ const model = strapi2.getModel(uid2);
3969
+ const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
3970
+ const traversalFunction = async (localeVersion) => traverseEntity(
3971
+ ({ key }, { remove }) => {
3972
+ if (keysToKeep.includes(key)) {
3973
+ return;
3974
+ }
3975
+ remove(key);
3976
+ },
3977
+ { schema: model, getModel: strapi2.getModel.bind(strapi2) },
3978
+ // @ts-expect-error fix types DocumentVersion incompatible with Data
3979
+ localeVersion
3980
+ );
3981
+ const mappingResult = await async.map(
3982
+ Object.values(versionsByLocale),
3983
+ async (localeVersions) => {
3984
+ const mappedLocaleVersions = await async.map(
3985
+ localeVersions,
3986
+ traversalFunction
3987
+ );
3988
+ if (!contentTypes$1.hasDraftAndPublish(model)) {
3989
+ return mappedLocaleVersions[0];
3990
+ }
3991
+ const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
3992
+ const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
3993
+ if (!draftVersion) {
3994
+ return;
3995
+ }
3996
+ return {
3997
+ ...draftVersion,
3998
+ status: this.getStatus(draftVersion, otherVersions)
3999
+ };
3891
4000
  }
3892
- const draftVersion = localeVersions.find((v) => v.publishedAt === null);
3893
- const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
3894
- if (!draftVersion)
3895
- return;
3896
- return {
3897
- ...pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
3898
- status: this.getStatus(draftVersion, otherVersions)
3899
- };
3900
- }).filter(Boolean);
4001
+ );
4002
+ return mappingResult.filter(Boolean);
3901
4003
  },
3902
4004
  /**
3903
4005
  * Returns available status of a document for the current locale
@@ -3935,26 +4037,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3935
4037
  });
3936
4038
  },
3937
4039
  getStatus(version, otherDocumentStatuses) {
3938
- const isDraft = version.publishedAt === null;
3939
- if (!otherDocumentStatuses?.length) {
3940
- return isDraft ? CONTENT_MANAGER_STATUS.DRAFT : CONTENT_MANAGER_STATUS.PUBLISHED;
4040
+ let draftVersion;
4041
+ let publishedVersion;
4042
+ if (version.publishedAt) {
4043
+ publishedVersion = version;
4044
+ } else {
4045
+ draftVersion = version;
3941
4046
  }
3942
- if (isDraft) {
3943
- const publishedVersion = otherDocumentStatuses?.find((d) => d.publishedAt !== null);
3944
- if (!publishedVersion) {
3945
- return CONTENT_MANAGER_STATUS.DRAFT;
3946
- }
4047
+ const otherVersion = otherDocumentStatuses?.at(0);
4048
+ if (otherVersion?.publishedAt) {
4049
+ publishedVersion = otherVersion;
4050
+ } else if (otherVersion) {
4051
+ draftVersion = otherVersion;
3947
4052
  }
3948
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
4053
+ if (!draftVersion)
3949
4054
  return CONTENT_MANAGER_STATUS.PUBLISHED;
3950
- }
3951
- return CONTENT_MANAGER_STATUS.MODIFIED;
4055
+ if (!publishedVersion)
4056
+ return CONTENT_MANAGER_STATUS.DRAFT;
4057
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4058
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3952
4059
  },
4060
+ // TODO is it necessary to return metadata on every page of the CM
4061
+ // We could refactor this so the locales are only loaded when they're
4062
+ // needed. e.g. in the bulk locale action modal.
3953
4063
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4064
+ const populate = getValidatableFieldsPopulate(uid2);
3954
4065
  const versions = await strapi2.db.query(uid2).findMany({
3955
4066
  where: { documentId: version.documentId },
3956
- select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
3957
4067
  populate: {
4068
+ // Populate only fields that require validation for bulk locale actions
4069
+ ...populate,
4070
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3958
4071
  createdBy: {
3959
4072
  select: ["id", "firstname", "lastname", "email"]
3960
4073
  },
@@ -3963,7 +4076,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3963
4076
  }
3964
4077
  }
3965
4078
  });
3966
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
4079
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
3967
4080
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3968
4081
  return {
3969
4082
  availableLocales: availableLocalesResult,
@@ -3976,8 +4089,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3976
4089
  * - Available status of the document for the current locale
3977
4090
  */
3978
4091
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3979
- if (!document)
4092
+ if (!document) {
3980
4093
  return document;
4094
+ }
3981
4095
  const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
3982
4096
  if (!hasDraftAndPublish) {
3983
4097
  opts.availableStatus = false;
@@ -4113,7 +4227,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4113
4227
  return {};
4114
4228
  },
4115
4229
  // FIXME: handle relations
4116
- async deleteMany(documentIds, uid2, opts) {
4230
+ async deleteMany(documentIds, uid2, opts = {}) {
4117
4231
  const deletedEntries = await strapi2.db.transaction(async () => {
4118
4232
  return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4119
4233
  });
@@ -4122,18 +4236,16 @@ const documentManager = ({ strapi: strapi2 }) => {
4122
4236
  async publish(id, uid2, opts = {}) {
4123
4237
  const populate = await buildDeepPopulate(uid2);
4124
4238
  const params = { ...opts, populate };
4125
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4239
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4126
4240
  },
4127
- async publishMany(documentIds, uid2, opts = {}) {
4128
- const publishedEntries = await strapi2.db.transaction(async () => {
4129
- return Promise.all(
4130
- documentIds.map(
4131
- (id) => strapi2.documents(uid2).publish({ ...opts, documentId: id }).then((result) => result?.entries)
4132
- )
4241
+ async publishMany(uid2, documentIds, locale) {
4242
+ return strapi2.db.transaction(async () => {
4243
+ const results = await Promise.all(
4244
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4133
4245
  );
4246
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4247
+ return publishedEntitiesCount;
4134
4248
  });
4135
- const publishedEntitiesCount = publishedEntries.flat().filter(Boolean).length;
4136
- return { count: publishedEntitiesCount };
4137
4249
  },
4138
4250
  async unpublishMany(documentIds, uid2, opts = {}) {
4139
4251
  const unpublishedEntries = await strapi2.db.transaction(async () => {
@@ -4174,14 +4286,18 @@ const documentManager = ({ strapi: strapi2 }) => {
4174
4286
  if (!hasRelations) {
4175
4287
  return 0;
4176
4288
  }
4177
- const documents = await strapi2.documents(uid2).findMany({
4289
+ let localeFilter = {};
4290
+ if (locale) {
4291
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4292
+ }
4293
+ const entities = await strapi2.db.query(uid2).findMany({
4178
4294
  populate,
4179
- filters: {
4180
- documentId: documentIds
4181
- },
4182
- locale
4295
+ where: {
4296
+ documentId: { $in: documentIds },
4297
+ ...localeFilter
4298
+ }
4183
4299
  });
4184
- const totalNumberDraftRelations = documents.reduce(
4300
+ const totalNumberDraftRelations = entities.reduce(
4185
4301
  (count, entity) => sumDraftCounts(entity, uid2) + count,
4186
4302
  0
4187
4303
  );