@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.2a7cb5ff33df35e8ccde5ef918f9f9a4a3ee9a08

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 (170) hide show
  1. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  3. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  4. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  5. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-BvHtG7uH.js} +3 -3
  6. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-BvHtG7uH.js.map} +1 -1
  7. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs → ComponentConfigurationPage-DHNM3YBz.mjs} +3 -3
  8. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-DHNM3YBz.mjs.map} +1 -1
  9. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  10. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  11. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  12. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  13. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs → EditConfigurationPage-Cp6HAEzN.mjs} +3 -3
  14. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-Cp6HAEzN.mjs.map} +1 -1
  15. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-DOmfCEMo.js} +3 -3
  16. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-DOmfCEMo.js.map} +1 -1
  17. package/dist/_chunks/{EditViewPage-KRG56aCq.js → EditViewPage-BqNpC6hO.js} +46 -48
  18. package/dist/_chunks/EditViewPage-BqNpC6hO.js.map +1 -0
  19. package/dist/_chunks/{EditViewPage-aUnqL-63.mjs → EditViewPage-BtkEx339.mjs} +47 -47
  20. package/dist/_chunks/EditViewPage-BtkEx339.mjs.map +1 -0
  21. package/dist/_chunks/{Field-kVFO4ZKB.mjs → Field-R5NbffTB.mjs} +854 -707
  22. package/dist/_chunks/Field-R5NbffTB.mjs.map +1 -0
  23. package/dist/_chunks/{Field-kq1c2TF1.js → Field-lsPFnAmH.js} +906 -760
  24. package/dist/_chunks/Field-lsPFnAmH.js.map +1 -0
  25. package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-BHmXSfyy.mjs} +39 -37
  26. package/dist/_chunks/Form-BHmXSfyy.mjs.map +1 -0
  27. package/dist/_chunks/{Form-CQ67ZifP.js → Form-CcGboku8.js} +39 -38
  28. package/dist/_chunks/Form-CcGboku8.js.map +1 -0
  29. package/dist/_chunks/{History-BLEnudTX.js → History-Bsud8jwh.js} +138 -51
  30. package/dist/_chunks/History-Bsud8jwh.js.map +1 -0
  31. package/dist/_chunks/{History-DKhZAPcK.mjs → History-ByUPL3T3.mjs} +137 -49
  32. package/dist/_chunks/History-ByUPL3T3.mjs.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-Bm5HACXf.mjs} +49 -51
  34. package/dist/_chunks/ListConfigurationPage-Bm5HACXf.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-DiT463qx.js} +53 -56
  36. package/dist/_chunks/ListConfigurationPage-DiT463qx.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-CsrC9L_d.js} +92 -108
  38. package/dist/_chunks/ListViewPage-CsrC9L_d.js.map +1 -0
  39. package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-JSyNAAYu.mjs} +87 -103
  40. package/dist/_chunks/ListViewPage-JSyNAAYu.mjs.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-Bsvng4II.js} +3 -3
  42. package/dist/_chunks/NoContentTypePage-Bsvng4II.js.map +1 -0
  43. package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-CsrQUpBE.mjs} +3 -3
  44. package/dist/_chunks/NoContentTypePage-CsrQUpBE.mjs.map +1 -0
  45. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-CdHNJtEf.js} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-CdHNJtEf.js.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-DNmf_pj0.mjs} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-DNmf_pj0.mjs.map} +1 -1
  49. package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-CghaPv2D.js} +70 -61
  50. package/dist/_chunks/Relations-CghaPv2D.js.map +1 -0
  51. package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-u8-37jK0.mjs} +66 -56
  52. package/dist/_chunks/Relations-u8-37jK0.mjs.map +1 -0
  53. package/dist/_chunks/{en-MBPul9Su.mjs → en-Ux26r5pl.mjs} +7 -1
  54. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-Ux26r5pl.mjs.map} +1 -1
  55. package/dist/_chunks/{en-C-V1_90f.js → en-fbKQxLGn.js} +7 -1
  56. package/dist/_chunks/{en-C-V1_90f.js.map → en-fbKQxLGn.js.map} +1 -1
  57. package/dist/_chunks/{index-DNa1J4HE.js → index-BOZx6IMg.js} +1481 -864
  58. package/dist/_chunks/index-BOZx6IMg.js.map +1 -0
  59. package/dist/_chunks/{index-CAc9yTnx.mjs → index-CaE6NG4a.mjs} +1450 -832
  60. package/dist/_chunks/index-CaE6NG4a.mjs.map +1 -0
  61. package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-Bx7svTbY.mjs} +28 -23
  62. package/dist/_chunks/layout-Bx7svTbY.mjs.map +1 -0
  63. package/dist/_chunks/{layout-BqtLA6Lb.js → layout-Ciz224q5.js} +29 -26
  64. package/dist/_chunks/layout-Ciz224q5.js.map +1 -0
  65. package/dist/_chunks/{relations-BHY_KDJ_.js → relations-CP8sB2YZ.js} +2 -2
  66. package/dist/_chunks/{relations-BHY_KDJ_.js.map → relations-CP8sB2YZ.js.map} +1 -1
  67. package/dist/_chunks/{relations-mMFEcZRq.mjs → relations-Cxc1cEv3.mjs} +2 -2
  68. package/dist/_chunks/{relations-mMFEcZRq.mjs.map → relations-Cxc1cEv3.mjs.map} +1 -1
  69. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  70. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  71. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  72. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  73. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  75. package/dist/admin/index.js +2 -1
  76. package/dist/admin/index.js.map +1 -1
  77. package/dist/admin/index.mjs +5 -4
  78. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  79. package/dist/admin/src/content-manager.d.ts +3 -3
  80. package/dist/admin/src/exports.d.ts +1 -0
  81. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  82. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  83. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  84. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  85. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  86. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  87. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  88. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +10 -4
  89. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  90. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  91. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  92. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  93. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +10 -18
  95. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  96. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  98. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +59 -52
  99. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  100. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  101. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  102. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  103. package/dist/admin/src/services/api.d.ts +2 -3
  104. package/dist/admin/src/services/components.d.ts +2 -2
  105. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  106. package/dist/admin/src/services/documents.d.ts +29 -17
  107. package/dist/admin/src/services/init.d.ts +2 -2
  108. package/dist/admin/src/services/relations.d.ts +3 -3
  109. package/dist/admin/src/services/uid.d.ts +3 -3
  110. package/dist/admin/src/utils/api.d.ts +4 -18
  111. package/dist/admin/src/utils/validation.d.ts +1 -6
  112. package/dist/server/index.js +293 -203
  113. package/dist/server/index.js.map +1 -1
  114. package/dist/server/index.mjs +295 -205
  115. package/dist/server/index.mjs.map +1 -1
  116. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  117. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  118. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  119. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  120. package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
  121. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  122. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  123. package/dist/server/src/history/services/history.d.ts.map +1 -1
  124. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  125. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  126. package/dist/server/src/index.d.ts +17 -33
  127. package/dist/server/src/index.d.ts.map +1 -1
  128. package/dist/server/src/services/document-manager.d.ts +11 -6
  129. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  130. package/dist/server/src/services/document-metadata.d.ts +8 -29
  131. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  132. package/dist/server/src/services/index.d.ts +17 -33
  133. package/dist/server/src/services/index.d.ts.map +1 -1
  134. package/dist/server/src/services/utils/populate.d.ts +8 -1
  135. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  136. package/dist/shared/contracts/collection-types.d.ts +14 -6
  137. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  138. package/dist/shared/contracts/relations.d.ts +2 -2
  139. package/dist/shared/contracts/relations.d.ts.map +1 -1
  140. package/package.json +13 -14
  141. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  142. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  143. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  144. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  145. package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
  146. package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
  147. package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
  148. package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
  149. package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
  150. package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
  151. package/dist/_chunks/History-BLEnudTX.js.map +0 -1
  152. package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
  153. package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
  154. package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
  155. package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
  156. package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
  157. package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
  158. package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
  159. package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
  160. package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
  161. package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
  162. package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
  163. package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
  164. package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
  165. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  166. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  167. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  168. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  169. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  170. 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, sanitize } 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";
@@ -206,6 +206,10 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
206
206
  return attributes.reduce((acc, [attributeName, attribute]) => {
207
207
  switch (attribute.type) {
208
208
  case "relation": {
209
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
210
+ if (isMorphRelation) {
211
+ break;
212
+ }
209
213
  const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
210
214
  if (isVisible2) {
211
215
  acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
@@ -469,8 +473,6 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
469
473
  deleteExpiredJob: null,
470
474
  isInitialized: false
471
475
  };
472
- const query = strapi2.db.query(HISTORY_VERSION_UID);
473
- const historyService = getService(strapi2, "history");
474
476
  const serviceUtils = createServiceUtils({ strapi: strapi2 });
475
477
  return {
476
478
  async bootstrap() {
@@ -481,7 +483,10 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
481
483
  if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
482
484
  return next();
483
485
  }
484
- if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
486
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
487
+ return next();
488
+ }
489
+ if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
485
490
  return next();
486
491
  }
487
492
  const contentTypeUid = context.contentType.uid;
@@ -489,9 +494,18 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
489
494
  return next();
490
495
  }
491
496
  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 };
497
+ const documentContext = {
498
+ documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
499
+ locale: context.params?.locale
500
+ };
493
501
  const defaultLocale = await serviceUtils.getDefaultLocale();
494
502
  const locale = documentContext.locale || defaultLocale;
503
+ if (Array.isArray(locale)) {
504
+ strapi2.log.warn(
505
+ "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
506
+ );
507
+ return next();
508
+ }
495
509
  const document = await strapi2.documents(contentTypeUid).findOne({
496
510
  documentId: documentContext.documentId,
497
511
  locale,
@@ -514,7 +528,7 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
514
528
  }, {});
515
529
  await strapi2.db.transaction(async ({ onCommit }) => {
516
530
  onCommit(() => {
517
- historyService.createVersion({
531
+ getService(strapi2, "history").createVersion({
518
532
  contentType: contentTypeUid,
519
533
  data: omit(FIELDS_TO_IGNORE, document),
520
534
  schema: omit(FIELDS_TO_IGNORE, attributesSchema),
@@ -527,11 +541,10 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
527
541
  });
528
542
  return result;
529
543
  });
530
- const retentionDays = serviceUtils.getRetentionDays();
531
544
  state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
532
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
545
+ const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
533
546
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
534
- query.deleteMany({
547
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
535
548
  where: {
536
549
  created_at: {
537
550
  $lt: expirationDate.toISOString()
@@ -1452,7 +1465,7 @@ const { PaginationError, ValidationError } = errors;
1452
1465
  const TYPES = ["singleType", "collectionType"];
1453
1466
  const kindSchema = yup$1.string().oneOf(TYPES).nullable();
1454
1467
  const bulkActionInputSchema = yup$1.object({
1455
- ids: yup$1.array().of(yup$1.strapiID()).min(1).required()
1468
+ documentIds: yup$1.array().of(yup$1.strapiID()).min(1).required()
1456
1469
  }).required();
1457
1470
  const generateUIDInputSchema = yup$1.object({
1458
1471
  contentTypeUID: yup$1.string().required(),
@@ -1551,15 +1564,47 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1551
1564
  }
1552
1565
  }, body);
1553
1566
  };
1554
- const getDocumentLocaleAndStatus = (request) => {
1567
+ const singleLocaleSchema = yup$1.string().nullable();
1568
+ const multipleLocaleSchema = yup$1.lazy(
1569
+ (value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1570
+ );
1571
+ const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
1572
+ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1573
+ const { allowMultipleLocales } = opts;
1555
1574
  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}`);
1575
+ const schema = yup$1.object().shape({
1576
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1577
+ status: statusSchema
1578
+ });
1579
+ try {
1580
+ await validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1581
+ return { locale, status, ...rest };
1582
+ } catch (error) {
1583
+ throw new errors.ValidationError(`Validation error: ${error.message}`);
1561
1584
  }
1562
- return { locale, status, ...rest };
1585
+ };
1586
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1587
+ const documentMetadata2 = getService$1("document-metadata");
1588
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1589
+ let {
1590
+ meta: { availableLocales, availableStatus }
1591
+ } = serviceOutput;
1592
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1593
+ availableLocales = await async.map(
1594
+ availableLocales,
1595
+ async (localeDocument) => metadataSanitizer(localeDocument)
1596
+ );
1597
+ availableStatus = await async.map(
1598
+ availableStatus,
1599
+ async (statusDocument) => metadataSanitizer(statusDocument)
1600
+ );
1601
+ return {
1602
+ ...serviceOutput,
1603
+ meta: {
1604
+ availableLocales,
1605
+ availableStatus
1606
+ }
1607
+ };
1563
1608
  };
1564
1609
  const createDocument = async (ctx, opts) => {
1565
1610
  const { userAbility, user } = ctx.state;
@@ -1574,7 +1619,7 @@ const createDocument = async (ctx, opts) => {
1574
1619
  const setCreator = setCreatorFields({ user });
1575
1620
  const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
1576
1621
  const sanitizedBody = await sanitizeFn(body);
1577
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1622
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1578
1623
  return documentManager2.create(model, {
1579
1624
  data: sanitizedBody,
1580
1625
  locale,
@@ -1593,7 +1638,7 @@ const updateDocument = async (ctx, opts) => {
1593
1638
  }
1594
1639
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1595
1640
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1596
- const { locale } = getDocumentLocaleAndStatus(body);
1641
+ const { locale } = await getDocumentLocaleAndStatus(body);
1597
1642
  const [documentVersion, documentExists] = await Promise.all([
1598
1643
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1599
1644
  documentManager2.exists(model, id)
@@ -1631,7 +1676,7 @@ const collectionTypes = {
1631
1676
  }
1632
1677
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1633
1678
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1634
- const { locale, status } = getDocumentLocaleAndStatus(query);
1679
+ const { locale, status } = await getDocumentLocaleAndStatus(query);
1635
1680
  const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
1636
1681
  { ...permissionQuery, populate, locale, status },
1637
1682
  model
@@ -1660,14 +1705,13 @@ const collectionTypes = {
1660
1705
  const { userAbility } = ctx.state;
1661
1706
  const { model, id } = ctx.params;
1662
1707
  const documentManager2 = getService$1("document-manager");
1663
- const documentMetadata2 = getService$1("document-metadata");
1664
1708
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1665
1709
  if (permissionChecker2.cannot.read()) {
1666
1710
  return ctx.forbidden();
1667
1711
  }
1668
1712
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1669
1713
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1670
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
1714
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1671
1715
  const version = await documentManager2.findOne(id, model, {
1672
1716
  populate,
1673
1717
  locale,
@@ -1678,8 +1722,10 @@ const collectionTypes = {
1678
1722
  if (!exists) {
1679
1723
  return ctx.notFound();
1680
1724
  }
1681
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
1725
+ const { meta } = await formatDocumentWithMetadata(
1726
+ permissionChecker2,
1682
1727
  model,
1728
+ // @ts-expect-error TODO: fix
1683
1729
  { id, locale, publishedAt: null },
1684
1730
  { availableLocales: true, availableStatus: false }
1685
1731
  );
@@ -1690,12 +1736,11 @@ const collectionTypes = {
1690
1736
  return ctx.forbidden();
1691
1737
  }
1692
1738
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1693
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1739
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1694
1740
  },
1695
1741
  async create(ctx) {
1696
1742
  const { userAbility } = ctx.state;
1697
1743
  const { model } = ctx.params;
1698
- const documentMetadata2 = getService$1("document-metadata");
1699
1744
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1700
1745
  const [totalEntries, document] = await Promise.all([
1701
1746
  strapi.db.query(model).count(),
@@ -1703,7 +1748,7 @@ const collectionTypes = {
1703
1748
  ]);
1704
1749
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1705
1750
  ctx.status = 201;
1706
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1751
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1707
1752
  // Empty metadata as it's not relevant for a new document
1708
1753
  availableLocales: false,
1709
1754
  availableStatus: false
@@ -1717,25 +1762,23 @@ const collectionTypes = {
1717
1762
  async update(ctx) {
1718
1763
  const { userAbility } = ctx.state;
1719
1764
  const { model } = ctx.params;
1720
- const documentMetadata2 = getService$1("document-metadata");
1721
1765
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1722
1766
  const updatedVersion = await updateDocument(ctx);
1723
1767
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1724
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
1768
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1725
1769
  },
1726
1770
  async clone(ctx) {
1727
1771
  const { userAbility, user } = ctx.state;
1728
1772
  const { model, sourceId: id } = ctx.params;
1729
1773
  const { body } = ctx.request;
1730
1774
  const documentManager2 = getService$1("document-manager");
1731
- const documentMetadata2 = getService$1("document-metadata");
1732
1775
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1733
1776
  if (permissionChecker2.cannot.create()) {
1734
1777
  return ctx.forbidden();
1735
1778
  }
1736
1779
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1737
1780
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1738
- const { locale } = getDocumentLocaleAndStatus(body);
1781
+ const { locale } = await getDocumentLocaleAndStatus(body);
1739
1782
  const document = await documentManager2.findOne(id, model, {
1740
1783
  populate,
1741
1784
  locale,
@@ -1751,7 +1794,7 @@ const collectionTypes = {
1751
1794
  const sanitizedBody = await sanitizeFn(body);
1752
1795
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1753
1796
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1754
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1797
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1755
1798
  // Empty metadata as it's not relevant for a new document
1756
1799
  availableLocales: false,
1757
1800
  availableStatus: false
@@ -1780,7 +1823,7 @@ const collectionTypes = {
1780
1823
  }
1781
1824
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1782
1825
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1783
- const { locale } = getDocumentLocaleAndStatus(ctx.query);
1826
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query);
1784
1827
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1785
1828
  if (documentLocales.length === 0) {
1786
1829
  return ctx.notFound();
@@ -1802,7 +1845,6 @@ const collectionTypes = {
1802
1845
  const { id, model } = ctx.params;
1803
1846
  const { body } = ctx.request;
1804
1847
  const documentManager2 = getService$1("document-manager");
1805
- const documentMetadata2 = getService$1("document-metadata");
1806
1848
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1807
1849
  if (permissionChecker2.cannot.publish()) {
1808
1850
  return ctx.forbidden();
@@ -1814,21 +1856,25 @@ const collectionTypes = {
1814
1856
  if (permissionChecker2.cannot.publish(document)) {
1815
1857
  throw new errors.ForbiddenError();
1816
1858
  }
1817
- const { locale } = getDocumentLocaleAndStatus(body);
1818
- return documentManager2.publish(document.documentId, model, {
1859
+ const { locale } = await getDocumentLocaleAndStatus(body);
1860
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1819
1861
  locale
1820
1862
  // TODO: Allow setting creator fields on publish
1821
1863
  // data: setCreatorFields({ user, isEdition: true })({}),
1822
1864
  });
1865
+ if (!publishResult || publishResult.length === 0) {
1866
+ throw new errors.NotFoundError("Document not found or already published.");
1867
+ }
1868
+ return publishResult[0];
1823
1869
  });
1824
1870
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1825
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1871
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1826
1872
  },
1827
1873
  async bulkPublish(ctx) {
1828
1874
  const { userAbility } = ctx.state;
1829
1875
  const { model } = ctx.params;
1830
1876
  const { body } = ctx.request;
1831
- const { ids } = body;
1877
+ const { documentIds } = body;
1832
1878
  await validateBulkActionInput(body);
1833
1879
  const documentManager2 = getService$1("document-manager");
1834
1880
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
@@ -1837,8 +1883,11 @@ const collectionTypes = {
1837
1883
  }
1838
1884
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1839
1885
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1840
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1841
- const entities = await Promise.all(entityPromises);
1886
+ const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
1887
+ const entityPromises = documentIds.map(
1888
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1889
+ );
1890
+ const entities = (await Promise.all(entityPromises)).flat();
1842
1891
  for (const entity of entities) {
1843
1892
  if (!entity) {
1844
1893
  return ctx.notFound();
@@ -1847,24 +1896,25 @@ const collectionTypes = {
1847
1896
  return ctx.forbidden();
1848
1897
  }
1849
1898
  }
1850
- const { count } = await documentManager2.publishMany(entities, model);
1899
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1851
1900
  ctx.body = { count };
1852
1901
  },
1853
1902
  async bulkUnpublish(ctx) {
1854
1903
  const { userAbility } = ctx.state;
1855
1904
  const { model } = ctx.params;
1856
1905
  const { body } = ctx.request;
1857
- const { ids } = body;
1906
+ const { documentIds } = body;
1858
1907
  await validateBulkActionInput(body);
1859
1908
  const documentManager2 = getService$1("document-manager");
1860
1909
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1861
1910
  if (permissionChecker2.cannot.unpublish()) {
1862
1911
  return ctx.forbidden();
1863
1912
  }
1864
- const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1865
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1866
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1867
- const entities = await Promise.all(entityPromises);
1913
+ const { locale } = await getDocumentLocaleAndStatus(body);
1914
+ const entityPromises = documentIds.map(
1915
+ (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1916
+ );
1917
+ const entities = (await Promise.all(entityPromises)).flat();
1868
1918
  for (const entity of entities) {
1869
1919
  if (!entity) {
1870
1920
  return ctx.notFound();
@@ -1873,7 +1923,8 @@ const collectionTypes = {
1873
1923
  return ctx.forbidden();
1874
1924
  }
1875
1925
  }
1876
- const { count } = await documentManager2.unpublishMany(entities, model);
1926
+ const entitiesIds = entities.map((document) => document.documentId);
1927
+ const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
1877
1928
  ctx.body = { count };
1878
1929
  },
1879
1930
  async unpublish(ctx) {
@@ -1883,7 +1934,6 @@ const collectionTypes = {
1883
1934
  body: { discardDraft, ...body }
1884
1935
  } = ctx.request;
1885
1936
  const documentManager2 = getService$1("document-manager");
1886
- const documentMetadata2 = getService$1("document-metadata");
1887
1937
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1888
1938
  if (permissionChecker2.cannot.unpublish()) {
1889
1939
  return ctx.forbidden();
@@ -1893,7 +1943,7 @@ const collectionTypes = {
1893
1943
  }
1894
1944
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1895
1945
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1896
- const { locale } = getDocumentLocaleAndStatus(body);
1946
+ const { locale } = await getDocumentLocaleAndStatus(body);
1897
1947
  const document = await documentManager2.findOne(id, model, {
1898
1948
  populate,
1899
1949
  locale,
@@ -1915,7 +1965,7 @@ const collectionTypes = {
1915
1965
  ctx.body = await async.pipe(
1916
1966
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1917
1967
  permissionChecker2.sanitizeOutput,
1918
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
1968
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1919
1969
  )(document);
1920
1970
  });
1921
1971
  },
@@ -1924,14 +1974,13 @@ const collectionTypes = {
1924
1974
  const { id, model } = ctx.params;
1925
1975
  const { body } = ctx.request;
1926
1976
  const documentManager2 = getService$1("document-manager");
1927
- const documentMetadata2 = getService$1("document-metadata");
1928
1977
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1929
1978
  if (permissionChecker2.cannot.discard()) {
1930
1979
  return ctx.forbidden();
1931
1980
  }
1932
1981
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1933
1982
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1934
- const { locale } = getDocumentLocaleAndStatus(body);
1983
+ const { locale } = await getDocumentLocaleAndStatus(body);
1935
1984
  const document = await documentManager2.findOne(id, model, {
1936
1985
  populate,
1937
1986
  locale,
@@ -1946,14 +1995,14 @@ const collectionTypes = {
1946
1995
  ctx.body = await async.pipe(
1947
1996
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1948
1997
  permissionChecker2.sanitizeOutput,
1949
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
1998
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1950
1999
  )(document);
1951
2000
  },
1952
2001
  async bulkDelete(ctx) {
1953
2002
  const { userAbility } = ctx.state;
1954
2003
  const { model } = ctx.params;
1955
2004
  const { query, body } = ctx.request;
1956
- const { ids } = body;
2005
+ const { documentIds } = body;
1957
2006
  await validateBulkActionInput(body);
1958
2007
  const documentManager2 = getService$1("document-manager");
1959
2008
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
@@ -1961,14 +2010,22 @@ const collectionTypes = {
1961
2010
  return ctx.forbidden();
1962
2011
  }
1963
2012
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
1964
- const idsWhereClause = { id: { $in: ids } };
1965
- const params = {
1966
- ...permissionQuery,
1967
- filters: {
1968
- $and: [idsWhereClause].concat(permissionQuery.filters || [])
2013
+ const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2014
+ const { locale } = await getDocumentLocaleAndStatus(body);
2015
+ const documentLocales = await documentManager2.findLocales(documentIds, model, {
2016
+ populate,
2017
+ locale
2018
+ });
2019
+ if (documentLocales.length === 0) {
2020
+ return ctx.notFound();
2021
+ }
2022
+ for (const document of documentLocales) {
2023
+ if (permissionChecker2.cannot.delete(document)) {
2024
+ return ctx.forbidden();
1969
2025
  }
1970
- };
1971
- const { count } = await documentManager2.deleteMany(params, model);
2026
+ }
2027
+ const localeDocumentsIds = documentLocales.map((document) => document.documentId);
2028
+ const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
1972
2029
  ctx.body = { count };
1973
2030
  },
1974
2031
  async countDraftRelations(ctx) {
@@ -1981,7 +2038,7 @@ const collectionTypes = {
1981
2038
  }
1982
2039
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1983
2040
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1984
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
2041
+ const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1985
2042
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
1986
2043
  if (!entity) {
1987
2044
  return ctx.notFound();
@@ -1996,7 +2053,7 @@ const collectionTypes = {
1996
2053
  },
1997
2054
  async countManyEntriesDraftRelations(ctx) {
1998
2055
  const { userAbility } = ctx.state;
1999
- const ids = ctx.request.query.ids;
2056
+ const ids = ctx.request.query.documentIds;
2000
2057
  const locale = ctx.request.query.locale;
2001
2058
  const { model } = ctx.params;
2002
2059
  const documentManager2 = getService$1("document-manager");
@@ -2004,16 +2061,16 @@ const collectionTypes = {
2004
2061
  if (permissionChecker2.cannot.read()) {
2005
2062
  return ctx.forbidden();
2006
2063
  }
2007
- const entities = await documentManager2.findMany(
2064
+ const documents = await documentManager2.findMany(
2008
2065
  {
2009
2066
  filters: {
2010
- id: ids
2067
+ documentId: ids
2011
2068
  },
2012
2069
  locale
2013
2070
  },
2014
2071
  model
2015
2072
  );
2016
- if (!entities) {
2073
+ if (!documents) {
2017
2074
  return ctx.notFound();
2018
2075
  }
2019
2076
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2509,7 +2566,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2509
2566
  throw new errors.ForbiddenError();
2510
2567
  }
2511
2568
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2512
- const { locale } = getDocumentLocaleAndStatus(body);
2569
+ const { locale } = await getDocumentLocaleAndStatus(body);
2513
2570
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2514
2571
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2515
2572
  // Find the first document to check if it exists
@@ -2546,12 +2603,11 @@ const singleTypes = {
2546
2603
  const { model } = ctx.params;
2547
2604
  const { query = {} } = ctx.request;
2548
2605
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2549
- const documentMetadata2 = getService$1("document-metadata");
2550
2606
  if (permissionChecker2.cannot.read()) {
2551
2607
  return ctx.forbidden();
2552
2608
  }
2553
2609
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2554
- const { locale, status } = getDocumentLocaleAndStatus(query);
2610
+ const { locale, status } = await getDocumentLocaleAndStatus(query);
2555
2611
  const version = await findDocument(permissionQuery, model, { locale, status });
2556
2612
  if (!version) {
2557
2613
  if (permissionChecker2.cannot.create()) {
@@ -2561,8 +2617,10 @@ const singleTypes = {
2561
2617
  if (!document) {
2562
2618
  return ctx.notFound();
2563
2619
  }
2564
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2620
+ const { meta } = await formatDocumentWithMetadata(
2621
+ permissionChecker2,
2565
2622
  model,
2623
+ // @ts-expect-error - fix types
2566
2624
  { id: document.documentId, locale, publishedAt: null },
2567
2625
  { availableLocales: true, availableStatus: false }
2568
2626
  );
@@ -2573,16 +2631,15 @@ const singleTypes = {
2573
2631
  return ctx.forbidden();
2574
2632
  }
2575
2633
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2576
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2634
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2577
2635
  },
2578
2636
  async createOrUpdate(ctx) {
2579
2637
  const { userAbility } = ctx.state;
2580
2638
  const { model } = ctx.params;
2581
- const documentMetadata2 = getService$1("document-metadata");
2582
2639
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2583
2640
  const document = await createOrUpdateDocument(ctx);
2584
2641
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2585
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2642
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2586
2643
  },
2587
2644
  async delete(ctx) {
2588
2645
  const { userAbility } = ctx.state;
@@ -2595,7 +2652,7 @@ const singleTypes = {
2595
2652
  }
2596
2653
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2597
2654
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2598
- const { locale } = getDocumentLocaleAndStatus(query);
2655
+ const { locale } = await getDocumentLocaleAndStatus(query);
2599
2656
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2600
2657
  populate,
2601
2658
  locale
@@ -2618,7 +2675,6 @@ const singleTypes = {
2618
2675
  const { model } = ctx.params;
2619
2676
  const { query = {} } = ctx.request;
2620
2677
  const documentManager2 = getService$1("document-manager");
2621
- const documentMetadata2 = getService$1("document-metadata");
2622
2678
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2623
2679
  if (permissionChecker2.cannot.publish()) {
2624
2680
  return ctx.forbidden();
@@ -2633,11 +2689,12 @@ const singleTypes = {
2633
2689
  if (permissionChecker2.cannot.publish(document)) {
2634
2690
  throw new errors.ForbiddenError();
2635
2691
  }
2636
- const { locale } = getDocumentLocaleAndStatus(document);
2637
- return documentManager2.publish(document.documentId, model, { locale });
2692
+ const { locale } = await getDocumentLocaleAndStatus(document);
2693
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2694
+ return publishResult.at(0);
2638
2695
  });
2639
2696
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2640
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2697
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2641
2698
  },
2642
2699
  async unpublish(ctx) {
2643
2700
  const { userAbility } = ctx.state;
@@ -2647,7 +2704,6 @@ const singleTypes = {
2647
2704
  query = {}
2648
2705
  } = ctx.request;
2649
2706
  const documentManager2 = getService$1("document-manager");
2650
- const documentMetadata2 = getService$1("document-metadata");
2651
2707
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2652
2708
  if (permissionChecker2.cannot.unpublish()) {
2653
2709
  return ctx.forbidden();
@@ -2656,7 +2712,7 @@ const singleTypes = {
2656
2712
  return ctx.forbidden();
2657
2713
  }
2658
2714
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2659
- const { locale } = getDocumentLocaleAndStatus(body);
2715
+ const { locale } = await getDocumentLocaleAndStatus(body);
2660
2716
  const document = await findDocument(sanitizedQuery, model, { locale });
2661
2717
  if (!document) {
2662
2718
  return ctx.notFound();
@@ -2674,7 +2730,7 @@ const singleTypes = {
2674
2730
  ctx.body = await async.pipe(
2675
2731
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2676
2732
  permissionChecker2.sanitizeOutput,
2677
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2733
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2678
2734
  )(document);
2679
2735
  });
2680
2736
  },
@@ -2683,13 +2739,12 @@ const singleTypes = {
2683
2739
  const { model } = ctx.params;
2684
2740
  const { body, query = {} } = ctx.request;
2685
2741
  const documentManager2 = getService$1("document-manager");
2686
- const documentMetadata2 = getService$1("document-metadata");
2687
2742
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2688
2743
  if (permissionChecker2.cannot.discard()) {
2689
2744
  return ctx.forbidden();
2690
2745
  }
2691
2746
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2692
- const { locale } = getDocumentLocaleAndStatus(body);
2747
+ const { locale } = await getDocumentLocaleAndStatus(body);
2693
2748
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2694
2749
  if (!document) {
2695
2750
  return ctx.notFound();
@@ -2700,7 +2755,7 @@ const singleTypes = {
2700
2755
  ctx.body = await async.pipe(
2701
2756
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2702
2757
  permissionChecker2.sanitizeOutput,
2703
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2758
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2704
2759
  )(document);
2705
2760
  },
2706
2761
  async countDraftRelations(ctx) {
@@ -2709,7 +2764,7 @@ const singleTypes = {
2709
2764
  const { query } = ctx.request;
2710
2765
  const documentManager2 = getService$1("document-manager");
2711
2766
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2712
- const { locale } = getDocumentLocaleAndStatus(query);
2767
+ const { locale } = await getDocumentLocaleAndStatus(query);
2713
2768
  if (permissionChecker2.cannot.read()) {
2714
2769
  return ctx.forbidden();
2715
2770
  }
@@ -2730,7 +2785,7 @@ const uid$1 = {
2730
2785
  async generateUID(ctx) {
2731
2786
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2732
2787
  const { query = {} } = ctx.request;
2733
- const { locale } = getDocumentLocaleAndStatus(query);
2788
+ const { locale } = await getDocumentLocaleAndStatus(query);
2734
2789
  await validateUIDField(contentTypeUID, field);
2735
2790
  const uidService = getService$1("uid");
2736
2791
  ctx.body = {
@@ -2742,7 +2797,7 @@ const uid$1 = {
2742
2797
  ctx.request.body
2743
2798
  );
2744
2799
  const { query = {} } = ctx.request;
2745
- const { locale } = getDocumentLocaleAndStatus(query);
2800
+ const { locale } = await getDocumentLocaleAndStatus(query);
2746
2801
  await validateUIDField(contentTypeUID, field);
2747
2802
  const uidService = getService$1("uid");
2748
2803
  const isAvailable = await uidService.checkUIDAvailability({
@@ -3533,7 +3588,7 @@ const permission = ({ strapi: strapi2 }) => ({
3533
3588
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3534
3589
  }
3535
3590
  });
3536
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils.contentTypes;
3591
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils.contentTypes;
3537
3592
  const { isAnyToMany } = strapiUtils.relations;
3538
3593
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils.contentTypes.constants;
3539
3594
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3624,6 +3679,42 @@ const getDeepPopulate = (uid2, {
3624
3679
  {}
3625
3680
  );
3626
3681
  };
3682
+ const getValidatableFieldsPopulate = (uid2, {
3683
+ initialPopulate = {},
3684
+ countMany = false,
3685
+ countOne = false,
3686
+ maxLevel = Infinity
3687
+ } = {}, level = 1) => {
3688
+ if (level > maxLevel) {
3689
+ return {};
3690
+ }
3691
+ const model = strapi.getModel(uid2);
3692
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3693
+ if (!getDoesAttributeRequireValidation(attribute)) {
3694
+ return populateAcc;
3695
+ }
3696
+ if (isScalarAttribute(attribute)) {
3697
+ return merge(populateAcc, {
3698
+ [attributeName]: true
3699
+ });
3700
+ }
3701
+ return merge(
3702
+ populateAcc,
3703
+ getPopulateFor(
3704
+ attributeName,
3705
+ model,
3706
+ {
3707
+ // @ts-expect-error - improve types
3708
+ initialPopulate: initialPopulate?.[attributeName],
3709
+ countMany,
3710
+ countOne,
3711
+ maxLevel
3712
+ },
3713
+ level
3714
+ )
3715
+ );
3716
+ }, {});
3717
+ };
3627
3718
  const getDeepPopulateDraftCount = (uid2) => {
3628
3719
  const model = strapi.getModel(uid2);
3629
3720
  let hasRelations = false;
@@ -3645,22 +3736,24 @@ const getDeepPopulateDraftCount = (uid2) => {
3645
3736
  attribute.component
3646
3737
  );
3647
3738
  if (childHasRelations) {
3648
- populateAcc[attributeName] = { populate: populate2 };
3739
+ populateAcc[attributeName] = {
3740
+ populate: populate2
3741
+ };
3649
3742
  hasRelations = true;
3650
3743
  }
3651
3744
  break;
3652
3745
  }
3653
3746
  case "dynamiczone": {
3654
- const dzPopulate = (attribute.components || []).reduce((acc, componentUID) => {
3655
- const { populate: populate2, hasRelations: childHasRelations } = getDeepPopulateDraftCount(componentUID);
3656
- if (childHasRelations) {
3747
+ const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
3748
+ const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
3749
+ if (componentHasRelations) {
3657
3750
  hasRelations = true;
3658
- return merge(acc, populate2);
3751
+ return { ...acc, [componentUID]: { populate: componentPopulate } };
3659
3752
  }
3660
3753
  return acc;
3661
3754
  }, {});
3662
- if (!isEmpty(dzPopulate)) {
3663
- populateAcc[attributeName] = { populate: dzPopulate };
3755
+ if (!isEmpty(dzPopulateFragment)) {
3756
+ populateAcc[attributeName] = { on: dzPopulateFragment };
3664
3757
  }
3665
3758
  break;
3666
3759
  }
@@ -3852,41 +3945,70 @@ const AVAILABLE_STATUS_FIELDS = [
3852
3945
  "updatedBy",
3853
3946
  "status"
3854
3947
  ];
3855
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
3948
+ const AVAILABLE_LOCALES_FIELDS = [
3949
+ "id",
3950
+ "locale",
3951
+ "updatedAt",
3952
+ "createdAt",
3953
+ "status",
3954
+ "publishedAt",
3955
+ "documentId"
3956
+ ];
3856
3957
  const CONTENT_MANAGER_STATUS = {
3857
3958
  PUBLISHED: "published",
3858
3959
  DRAFT: "draft",
3859
3960
  MODIFIED: "modified"
3860
3961
  };
3861
- const areDatesEqual = (date1, date2, threshold) => {
3862
- if (!date1 || !date2) {
3962
+ const getIsVersionLatestModification = (version, otherVersion) => {
3963
+ if (!version || !version.updatedAt) {
3863
3964
  return false;
3864
3965
  }
3865
- const time1 = new Date(date1).getTime();
3866
- const time2 = new Date(date2).getTime();
3867
- const difference2 = Math.abs(time1 - time2);
3868
- return difference2 <= threshold;
3966
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
3967
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
3968
+ return versionUpdatedAt > otherUpdatedAt;
3869
3969
  };
3870
3970
  const documentMetadata = ({ strapi: strapi2 }) => ({
3871
3971
  /**
3872
3972
  * Returns available locales of a document for the current status
3873
3973
  */
3874
- getAvailableLocales(uid2, version, allVersions) {
3974
+ async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
3875
3975
  const versionsByLocale = groupBy("locale", allVersions);
3876
3976
  delete versionsByLocale[version.locale];
3877
- return Object.values(versionsByLocale).map((localeVersions) => {
3878
- if (!contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2))) {
3879
- return pick(AVAILABLE_LOCALES_FIELDS, localeVersions[0]);
3977
+ const model = strapi2.getModel(uid2);
3978
+ const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
3979
+ const traversalFunction = async (localeVersion) => traverseEntity(
3980
+ ({ key }, { remove }) => {
3981
+ if (keysToKeep.includes(key)) {
3982
+ return;
3983
+ }
3984
+ remove(key);
3985
+ },
3986
+ { schema: model, getModel: strapi2.getModel.bind(strapi2) },
3987
+ // @ts-expect-error fix types DocumentVersion incompatible with Data
3988
+ localeVersion
3989
+ );
3990
+ const mappingResult = await async.map(
3991
+ Object.values(versionsByLocale),
3992
+ async (localeVersions) => {
3993
+ const mappedLocaleVersions = await async.map(
3994
+ localeVersions,
3995
+ traversalFunction
3996
+ );
3997
+ if (!contentTypes$1.hasDraftAndPublish(model)) {
3998
+ return mappedLocaleVersions[0];
3999
+ }
4000
+ const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4001
+ const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
4002
+ if (!draftVersion) {
4003
+ return;
4004
+ }
4005
+ return {
4006
+ ...draftVersion,
4007
+ status: this.getStatus(draftVersion, otherVersions)
4008
+ };
3880
4009
  }
3881
- const draftVersion = localeVersions.find((v) => v.publishedAt === null);
3882
- const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
3883
- if (!draftVersion)
3884
- return;
3885
- return {
3886
- ...pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
3887
- status: this.getStatus(draftVersion, otherVersions)
3888
- };
3889
- }).filter(Boolean);
4010
+ );
4011
+ return mappingResult.filter(Boolean);
3890
4012
  },
3891
4013
  /**
3892
4014
  * Returns available status of a document for the current locale
@@ -3924,26 +4046,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3924
4046
  });
3925
4047
  },
3926
4048
  getStatus(version, otherDocumentStatuses) {
3927
- const isDraft = version.publishedAt === null;
3928
- if (!otherDocumentStatuses?.length) {
3929
- return isDraft ? CONTENT_MANAGER_STATUS.DRAFT : CONTENT_MANAGER_STATUS.PUBLISHED;
4049
+ let draftVersion;
4050
+ let publishedVersion;
4051
+ if (version.publishedAt) {
4052
+ publishedVersion = version;
4053
+ } else {
4054
+ draftVersion = version;
3930
4055
  }
3931
- if (isDraft) {
3932
- const publishedVersion = otherDocumentStatuses?.find((d) => d.publishedAt !== null);
3933
- if (!publishedVersion) {
3934
- return CONTENT_MANAGER_STATUS.DRAFT;
3935
- }
4056
+ const otherVersion = otherDocumentStatuses?.at(0);
4057
+ if (otherVersion?.publishedAt) {
4058
+ publishedVersion = otherVersion;
4059
+ } else if (otherVersion) {
4060
+ draftVersion = otherVersion;
3936
4061
  }
3937
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
4062
+ if (!draftVersion)
3938
4063
  return CONTENT_MANAGER_STATUS.PUBLISHED;
3939
- }
3940
- return CONTENT_MANAGER_STATUS.MODIFIED;
4064
+ if (!publishedVersion)
4065
+ return CONTENT_MANAGER_STATUS.DRAFT;
4066
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4067
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3941
4068
  },
4069
+ // TODO is it necessary to return metadata on every page of the CM
4070
+ // We could refactor this so the locales are only loaded when they're
4071
+ // needed. e.g. in the bulk locale action modal.
3942
4072
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4073
+ const populate = getValidatableFieldsPopulate(uid2);
3943
4074
  const versions = await strapi2.db.query(uid2).findMany({
3944
4075
  where: { documentId: version.documentId },
3945
- select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
3946
4076
  populate: {
4077
+ // Populate only fields that require validation for bulk locale actions
4078
+ ...populate,
4079
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3947
4080
  createdBy: {
3948
4081
  select: ["id", "firstname", "lastname", "email"]
3949
4082
  },
@@ -3952,7 +4085,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3952
4085
  }
3953
4086
  }
3954
4087
  });
3955
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
4088
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
3956
4089
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3957
4090
  return {
3958
4091
  availableLocales: availableLocalesResult,
@@ -3965,8 +4098,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3965
4098
  * - Available status of the document for the current locale
3966
4099
  */
3967
4100
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3968
- if (!document)
4101
+ if (!document) {
3969
4102
  return document;
4103
+ }
3970
4104
  const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
3971
4105
  if (!hasDraftAndPublish) {
3972
4106
  opts.availableStatus = false;
@@ -4016,26 +4150,9 @@ const sumDraftCounts = (entity, uid2) => {
4016
4150
  }, 0);
4017
4151
  };
4018
4152
  const { ApplicationError } = errors;
4019
- const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
4020
4153
  const { PUBLISHED_AT_ATTRIBUTE } = contentTypes$1.constants;
4021
4154
  const omitPublishedAtField = omit(PUBLISHED_AT_ATTRIBUTE);
4022
4155
  const omitIdField = omit("id");
4023
- const emitEvent = async (uid2, event, document) => {
4024
- const modelDef = strapi.getModel(uid2);
4025
- const sanitizedDocument = await sanitize.sanitizers.defaultSanitizeOutput(
4026
- {
4027
- schema: modelDef,
4028
- getModel(uid22) {
4029
- return strapi.getModel(uid22);
4030
- }
4031
- },
4032
- document
4033
- );
4034
- strapi.eventHub.emit(event, {
4035
- model: modelDef.modelName,
4036
- entry: sanitizedDocument
4037
- });
4038
- };
4039
4156
  const documentManager = ({ strapi: strapi2 }) => {
4040
4157
  return {
4041
4158
  async findOne(id, uid2, opts = {}) {
@@ -4054,6 +4171,9 @@ const documentManager = ({ strapi: strapi2 }) => {
4054
4171
  } else if (opts.locale && opts.locale !== "*") {
4055
4172
  where.locale = opts.locale;
4056
4173
  }
4174
+ if (typeof opts.isPublished === "boolean") {
4175
+ where.publishedAt = { $notNull: opts.isPublished };
4176
+ }
4057
4177
  return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
4058
4178
  },
4059
4179
  async findMany(opts, uid2) {
@@ -4116,70 +4236,36 @@ const documentManager = ({ strapi: strapi2 }) => {
4116
4236
  return {};
4117
4237
  },
4118
4238
  // FIXME: handle relations
4119
- async deleteMany(opts, uid2) {
4120
- const docs = await strapi2.documents(uid2).findMany(opts);
4121
- for (const doc of docs) {
4122
- await strapi2.documents(uid2).delete({ documentId: doc.documentId });
4123
- }
4124
- return { count: docs.length };
4239
+ async deleteMany(documentIds, uid2, opts = {}) {
4240
+ const deletedEntries = await strapi2.db.transaction(async () => {
4241
+ return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4242
+ });
4243
+ return { count: deletedEntries.length };
4125
4244
  },
4126
4245
  async publish(id, uid2, opts = {}) {
4127
4246
  const populate = await buildDeepPopulate(uid2);
4128
4247
  const params = { ...opts, populate };
4129
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4248
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4130
4249
  },
4131
- async publishMany(entities, uid2) {
4132
- if (!entities.length) {
4133
- return null;
4134
- }
4135
- await Promise.all(
4136
- entities.map((document) => {
4137
- return strapi2.entityValidator.validateEntityCreation(
4138
- strapi2.getModel(uid2),
4139
- document,
4140
- void 0,
4141
- // @ts-expect-error - FIXME: entity here is unnecessary
4142
- document
4143
- );
4144
- })
4145
- );
4146
- const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4147
- const filters = { id: { $in: entitiesToPublish } };
4148
- const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
4149
- const populate = await buildDeepPopulate(uid2);
4150
- const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4151
- where: filters,
4152
- data
4153
- });
4154
- const publishedEntities = await strapi2.db.query(uid2).findMany({
4155
- where: filters,
4156
- populate
4250
+ async publishMany(uid2, documentIds, locale) {
4251
+ return strapi2.db.transaction(async () => {
4252
+ const results = await Promise.all(
4253
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4254
+ );
4255
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4256
+ return publishedEntitiesCount;
4157
4257
  });
4158
- await Promise.all(
4159
- publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
4160
- );
4161
- return publishedEntitiesCount;
4162
4258
  },
4163
- async unpublishMany(documents, uid2) {
4164
- if (!documents.length) {
4165
- return null;
4166
- }
4167
- const entitiesToUnpublish = documents.filter((doc) => doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4168
- const filters = { id: { $in: entitiesToUnpublish } };
4169
- const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
4170
- const populate = await buildDeepPopulate(uid2);
4171
- const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4172
- where: filters,
4173
- data
4174
- });
4175
- const unpublishedEntities = await strapi2.db.query(uid2).findMany({
4176
- where: filters,
4177
- populate
4259
+ async unpublishMany(documentIds, uid2, opts = {}) {
4260
+ const unpublishedEntries = await strapi2.db.transaction(async () => {
4261
+ return Promise.all(
4262
+ documentIds.map(
4263
+ (id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
4264
+ )
4265
+ );
4178
4266
  });
4179
- await Promise.all(
4180
- unpublishedEntities.map((doc) => emitEvent(uid2, ENTRY_UNPUBLISH, doc))
4181
- );
4182
- return unpublishedEntitiesCount;
4267
+ const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
4268
+ return { count: unpublishedEntitiesCount };
4183
4269
  },
4184
4270
  async unpublish(id, uid2, opts = {}) {
4185
4271
  const populate = await buildDeepPopulate(uid2);
@@ -4204,16 +4290,20 @@ const documentManager = ({ strapi: strapi2 }) => {
4204
4290
  }
4205
4291
  return sumDraftCounts(document, uid2);
4206
4292
  },
4207
- async countManyEntriesDraftRelations(ids, uid2, locale) {
4293
+ async countManyEntriesDraftRelations(documentIds, uid2, locale) {
4208
4294
  const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
4209
4295
  if (!hasRelations) {
4210
4296
  return 0;
4211
4297
  }
4298
+ let localeFilter = {};
4299
+ if (locale) {
4300
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4301
+ }
4212
4302
  const entities = await strapi2.db.query(uid2).findMany({
4213
4303
  populate,
4214
4304
  where: {
4215
- id: { $in: ids },
4216
- ...locale ? { locale } : {}
4305
+ documentId: { $in: documentIds },
4306
+ ...localeFilter
4217
4307
  }
4218
4308
  });
4219
4309
  const totalNumberDraftRelations = entities.reduce(