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

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