@strapi/content-manager 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.edc24aaa3bb5a90fa5fd4fee208167dd4e2e38d4

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 (174) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-5ukroXAh.js} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-5ukroXAh.js.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-BAgyHiMm.mjs} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-BAgyHiMm.mjs.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  11. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs → EditConfigurationPage-DmoXawIh.mjs} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-DmoXawIh.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-Xp7lun0f.js} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-Xp7lun0f.js.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-BLsjc5F-.mjs} +47 -47
  19. package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +1 -0
  20. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-C-ukDOB7.js} +46 -48
  21. package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +1 -0
  22. package/dist/_chunks/{Field-DmVKIAOo.js → Field-Bfph5SOd.js} +953 -782
  23. package/dist/_chunks/Field-Bfph5SOd.js.map +1 -0
  24. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-Cs7duwWd.mjs} +901 -729
  25. package/dist/_chunks/Field-Cs7duwWd.mjs.map +1 -0
  26. package/dist/_chunks/{Form-CPZC9vWa.js → Form-CPYqIWDG.js} +39 -38
  27. package/dist/_chunks/Form-CPYqIWDG.js.map +1 -0
  28. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-Dg_GS5TQ.mjs} +39 -37
  29. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +1 -0
  30. package/dist/_chunks/{History-DeAPlvtv.js → History-DNQkXANT.js} +149 -56
  31. package/dist/_chunks/History-DNQkXANT.js.map +1 -0
  32. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-wrnHqf09.mjs} +148 -54
  33. package/dist/_chunks/History-wrnHqf09.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-CUQxfpjT.js} +58 -59
  35. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-DScmJVkW.mjs} +54 -54
  37. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-BsLiH2-2.js} +92 -108
  39. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +1 -0
  40. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-C4IvrMgY.mjs} +87 -103
  41. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BZ-PnGAf.js} +3 -3
  43. package/dist/_chunks/NoContentTypePage-BZ-PnGAf.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Djg8nPlj.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-Djg8nPlj.mjs.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-DSP7R-hv.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-DSP7R-hv.mjs.map} +1 -1
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-_lUqjGW3.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-_lUqjGW3.js.map} +1 -1
  50. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-BZr8tL0R.mjs} +66 -56
  51. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-CtELXYIK.js} +70 -61
  53. package/dist/_chunks/Relations-CtELXYIK.js.map +1 -0
  54. package/dist/_chunks/{en-MBPul9Su.mjs → en-BrCTWlZv.mjs} +11 -4
  55. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  56. package/dist/_chunks/{en-C-V1_90f.js → en-uOUIxfcQ.js} +11 -4
  57. package/dist/_chunks/{en-C-V1_90f.js.map → en-uOUIxfcQ.js.map} +1 -1
  58. package/dist/_chunks/{index-C6AH2hEl.js → index-OerGjbAN.js} +1588 -837
  59. package/dist/_chunks/index-OerGjbAN.js.map +1 -0
  60. package/dist/_chunks/{index-CwRRo1V9.mjs → index-c_5DdJi-.mjs} +1610 -858
  61. package/dist/_chunks/index-c_5DdJi-.mjs.map +1 -0
  62. package/dist/_chunks/{layout-B_SXLhqf.js → layout-Ci7qHlFb.js} +30 -27
  63. package/dist/_chunks/layout-Ci7qHlFb.js.map +1 -0
  64. package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-oPBiO7RY.mjs} +29 -24
  65. package/dist/_chunks/layout-oPBiO7RY.mjs.map +1 -0
  66. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-BIdWFjdq.mjs} +2 -2
  67. package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-BIdWFjdq.mjs.map} +1 -1
  68. package/dist/_chunks/{relations-iBMa_OFG.js → relations-COBpStiF.js} +2 -2
  69. package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-COBpStiF.js.map} +1 -1
  70. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  71. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  72. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  73. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  75. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  76. package/dist/admin/index.js +2 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +5 -4
  79. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  80. package/dist/admin/src/content-manager.d.ts +3 -3
  81. package/dist/admin/src/exports.d.ts +1 -0
  82. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  83. package/dist/admin/src/history/index.d.ts +3 -0
  84. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  85. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  86. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  87. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  88. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  89. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  90. package/dist/admin/src/index.d.ts +1 -0
  91. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
  92. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  93. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  95. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  96. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  98. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  99. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  100. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  101. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +59 -52
  102. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  103. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  104. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  105. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  106. package/dist/admin/src/services/api.d.ts +2 -3
  107. package/dist/admin/src/services/components.d.ts +2 -2
  108. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  109. package/dist/admin/src/services/documents.d.ts +29 -17
  110. package/dist/admin/src/services/init.d.ts +2 -2
  111. package/dist/admin/src/services/relations.d.ts +3 -3
  112. package/dist/admin/src/services/uid.d.ts +3 -3
  113. package/dist/admin/src/utils/api.d.ts +4 -18
  114. package/dist/admin/src/utils/validation.d.ts +1 -6
  115. package/dist/server/index.js +309 -218
  116. package/dist/server/index.js.map +1 -1
  117. package/dist/server/index.mjs +317 -226
  118. package/dist/server/index.mjs.map +1 -1
  119. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  120. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  121. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  122. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  123. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  124. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  125. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  126. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  127. package/dist/server/src/history/services/history.d.ts.map +1 -1
  128. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  129. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  130. package/dist/server/src/index.d.ts +18 -39
  131. package/dist/server/src/index.d.ts.map +1 -1
  132. package/dist/server/src/services/document-manager.d.ts +13 -12
  133. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  134. package/dist/server/src/services/document-metadata.d.ts +8 -29
  135. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  136. package/dist/server/src/services/index.d.ts +18 -39
  137. package/dist/server/src/services/index.d.ts.map +1 -1
  138. package/dist/server/src/services/utils/populate.d.ts +8 -1
  139. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  140. package/dist/shared/contracts/collection-types.d.ts +14 -6
  141. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  142. package/dist/shared/contracts/relations.d.ts +2 -2
  143. package/dist/shared/contracts/relations.d.ts.map +1 -1
  144. package/package.json +13 -14
  145. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  146. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  147. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  148. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  149. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  150. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  151. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  152. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  153. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  154. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  155. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  156. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  157. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  158. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  159. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  160. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  161. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  162. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  163. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  164. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  165. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  166. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  167. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  168. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  169. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  170. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  171. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  172. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  173. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  174. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -232,6 +232,10 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
232
232
  return attributes.reduce((acc, [attributeName, attribute]) => {
233
233
  switch (attribute.type) {
234
234
  case "relation": {
235
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
236
+ if (isMorphRelation) {
237
+ break;
238
+ }
235
239
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
236
240
  if (isVisible2) {
237
241
  acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
@@ -495,8 +499,6 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
495
499
  deleteExpiredJob: null,
496
500
  isInitialized: false
497
501
  };
498
- const query = strapi2.db.query(HISTORY_VERSION_UID);
499
- const historyService = getService(strapi2, "history");
500
502
  const serviceUtils = createServiceUtils({ strapi: strapi2 });
501
503
  return {
502
504
  async bootstrap() {
@@ -507,7 +509,10 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
507
509
  if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
508
510
  return next();
509
511
  }
510
- if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
512
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
513
+ return next();
514
+ }
515
+ if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
511
516
  return next();
512
517
  }
513
518
  const contentTypeUid = context.contentType.uid;
@@ -515,9 +520,18 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
515
520
  return next();
516
521
  }
517
522
  const result = await next();
518
- const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
523
+ const documentContext = {
524
+ documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
525
+ locale: context.params?.locale
526
+ };
519
527
  const defaultLocale = await serviceUtils.getDefaultLocale();
520
528
  const locale = documentContext.locale || defaultLocale;
529
+ if (Array.isArray(locale)) {
530
+ strapi2.log.warn(
531
+ "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
532
+ );
533
+ return next();
534
+ }
521
535
  const document = await strapi2.documents(contentTypeUid).findOne({
522
536
  documentId: documentContext.documentId,
523
537
  locale,
@@ -540,7 +554,7 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
540
554
  }, {});
541
555
  await strapi2.db.transaction(async ({ onCommit }) => {
542
556
  onCommit(() => {
543
- historyService.createVersion({
557
+ getService(strapi2, "history").createVersion({
544
558
  contentType: contentTypeUid,
545
559
  data: fp.omit(FIELDS_TO_IGNORE, document),
546
560
  schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
@@ -553,11 +567,10 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
553
567
  });
554
568
  return result;
555
569
  });
556
- const retentionDays = serviceUtils.getRetentionDays();
557
570
  state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
558
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
571
+ const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
559
572
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
560
- query.deleteMany({
573
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
561
574
  where: {
562
575
  created_at: {
563
576
  $lt: expirationDate.toISOString()
@@ -1478,7 +1491,7 @@ const { PaginationError, ValidationError } = strapiUtils.errors;
1478
1491
  const TYPES = ["singleType", "collectionType"];
1479
1492
  const kindSchema = strapiUtils.yup.string().oneOf(TYPES).nullable();
1480
1493
  const bulkActionInputSchema = strapiUtils.yup.object({
1481
- ids: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
1494
+ documentIds: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
1482
1495
  }).required();
1483
1496
  const generateUIDInputSchema = strapiUtils.yup.object({
1484
1497
  contentTypeUID: strapiUtils.yup.string().required(),
@@ -1577,15 +1590,49 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1577
1590
  }
1578
1591
  }, body);
1579
1592
  };
1580
- const getDocumentLocaleAndStatus = (request) => {
1581
- const { locale, status, ...rest } = request || {};
1582
- if (!fp.isNil(locale) && typeof locale !== "string") {
1583
- throw new strapiUtils.errors.ValidationError(`Invalid locale: ${locale}`);
1584
- }
1585
- if (!fp.isNil(status) && !["draft", "published"].includes(status)) {
1586
- throw new strapiUtils.errors.ValidationError(`Invalid status: ${status}`);
1593
+ const singleLocaleSchema = strapiUtils.yup.string().nullable();
1594
+ const multipleLocaleSchema = strapiUtils.yup.lazy(
1595
+ (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1596
+ );
1597
+ const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1598
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1599
+ const { allowMultipleLocales } = opts;
1600
+ const { locale, status: providedStatus, ...rest } = request || {};
1601
+ const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1602
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1603
+ const schema = strapiUtils.yup.object().shape({
1604
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1605
+ status: statusSchema
1606
+ });
1607
+ try {
1608
+ await strapiUtils.validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1609
+ return { locale, status, ...rest };
1610
+ } catch (error) {
1611
+ throw new strapiUtils.errors.ValidationError(`Validation error: ${error.message}`);
1587
1612
  }
1588
- return { locale, status, ...rest };
1613
+ };
1614
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1615
+ const documentMetadata2 = getService$1("document-metadata");
1616
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1617
+ let {
1618
+ meta: { availableLocales, availableStatus }
1619
+ } = serviceOutput;
1620
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1621
+ availableLocales = await strapiUtils.async.map(
1622
+ availableLocales,
1623
+ async (localeDocument) => metadataSanitizer(localeDocument)
1624
+ );
1625
+ availableStatus = await strapiUtils.async.map(
1626
+ availableStatus,
1627
+ async (statusDocument) => metadataSanitizer(statusDocument)
1628
+ );
1629
+ return {
1630
+ ...serviceOutput,
1631
+ meta: {
1632
+ availableLocales,
1633
+ availableStatus
1634
+ }
1635
+ };
1589
1636
  };
1590
1637
  const createDocument = async (ctx, opts) => {
1591
1638
  const { userAbility, user } = ctx.state;
@@ -1600,7 +1647,7 @@ const createDocument = async (ctx, opts) => {
1600
1647
  const setCreator = strapiUtils.setCreatorFields({ user });
1601
1648
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1602
1649
  const sanitizedBody = await sanitizeFn(body);
1603
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1650
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1604
1651
  return documentManager2.create(model, {
1605
1652
  data: sanitizedBody,
1606
1653
  locale,
@@ -1619,7 +1666,7 @@ const updateDocument = async (ctx, opts) => {
1619
1666
  }
1620
1667
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1621
1668
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1622
- const { locale } = getDocumentLocaleAndStatus(body);
1669
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1623
1670
  const [documentVersion, documentExists] = await Promise.all([
1624
1671
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1625
1672
  documentManager2.exists(model, id)
@@ -1657,7 +1704,7 @@ const collectionTypes = {
1657
1704
  }
1658
1705
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1659
1706
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1660
- const { locale, status } = getDocumentLocaleAndStatus(query);
1707
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1661
1708
  const { results: documents, pagination } = await documentManager2.findPage(
1662
1709
  { ...permissionQuery, populate, locale, status },
1663
1710
  model
@@ -1686,14 +1733,13 @@ const collectionTypes = {
1686
1733
  const { userAbility } = ctx.state;
1687
1734
  const { model, id } = ctx.params;
1688
1735
  const documentManager2 = getService$1("document-manager");
1689
- const documentMetadata2 = getService$1("document-metadata");
1690
1736
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1691
1737
  if (permissionChecker2.cannot.read()) {
1692
1738
  return ctx.forbidden();
1693
1739
  }
1694
1740
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1695
1741
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1696
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
1742
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1697
1743
  const version = await documentManager2.findOne(id, model, {
1698
1744
  populate,
1699
1745
  locale,
@@ -1704,8 +1750,10 @@ const collectionTypes = {
1704
1750
  if (!exists) {
1705
1751
  return ctx.notFound();
1706
1752
  }
1707
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
1753
+ const { meta } = await formatDocumentWithMetadata(
1754
+ permissionChecker2,
1708
1755
  model,
1756
+ // @ts-expect-error TODO: fix
1709
1757
  { id, locale, publishedAt: null },
1710
1758
  { availableLocales: true, availableStatus: false }
1711
1759
  );
@@ -1716,12 +1764,11 @@ const collectionTypes = {
1716
1764
  return ctx.forbidden();
1717
1765
  }
1718
1766
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1719
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1767
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1720
1768
  },
1721
1769
  async create(ctx) {
1722
1770
  const { userAbility } = ctx.state;
1723
1771
  const { model } = ctx.params;
1724
- const documentMetadata2 = getService$1("document-metadata");
1725
1772
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1726
1773
  const [totalEntries, document] = await Promise.all([
1727
1774
  strapi.db.query(model).count(),
@@ -1729,7 +1776,7 @@ const collectionTypes = {
1729
1776
  ]);
1730
1777
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1731
1778
  ctx.status = 201;
1732
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1779
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1733
1780
  // Empty metadata as it's not relevant for a new document
1734
1781
  availableLocales: false,
1735
1782
  availableStatus: false
@@ -1743,25 +1790,23 @@ const collectionTypes = {
1743
1790
  async update(ctx) {
1744
1791
  const { userAbility } = ctx.state;
1745
1792
  const { model } = ctx.params;
1746
- const documentMetadata2 = getService$1("document-metadata");
1747
1793
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1748
1794
  const updatedVersion = await updateDocument(ctx);
1749
1795
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1750
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
1796
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1751
1797
  },
1752
1798
  async clone(ctx) {
1753
1799
  const { userAbility, user } = ctx.state;
1754
1800
  const { model, sourceId: id } = ctx.params;
1755
1801
  const { body } = ctx.request;
1756
1802
  const documentManager2 = getService$1("document-manager");
1757
- const documentMetadata2 = getService$1("document-metadata");
1758
1803
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1759
1804
  if (permissionChecker2.cannot.create()) {
1760
1805
  return ctx.forbidden();
1761
1806
  }
1762
1807
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1763
1808
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1764
- const { locale } = getDocumentLocaleAndStatus(body);
1809
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1765
1810
  const document = await documentManager2.findOne(id, model, {
1766
1811
  populate,
1767
1812
  locale,
@@ -1777,7 +1822,7 @@ const collectionTypes = {
1777
1822
  const sanitizedBody = await sanitizeFn(body);
1778
1823
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1779
1824
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1780
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
1825
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1781
1826
  // Empty metadata as it's not relevant for a new document
1782
1827
  availableLocales: false,
1783
1828
  availableStatus: false
@@ -1806,7 +1851,7 @@ const collectionTypes = {
1806
1851
  }
1807
1852
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1808
1853
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1809
- const { locale } = getDocumentLocaleAndStatus(ctx.query);
1854
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1810
1855
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1811
1856
  if (documentLocales.length === 0) {
1812
1857
  return ctx.notFound();
@@ -1828,7 +1873,6 @@ const collectionTypes = {
1828
1873
  const { id, model } = ctx.params;
1829
1874
  const { body } = ctx.request;
1830
1875
  const documentManager2 = getService$1("document-manager");
1831
- const documentMetadata2 = getService$1("document-metadata");
1832
1876
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1833
1877
  if (permissionChecker2.cannot.publish()) {
1834
1878
  return ctx.forbidden();
@@ -1840,21 +1884,25 @@ const collectionTypes = {
1840
1884
  if (permissionChecker2.cannot.publish(document)) {
1841
1885
  throw new strapiUtils.errors.ForbiddenError();
1842
1886
  }
1843
- const { locale } = getDocumentLocaleAndStatus(body);
1844
- return documentManager2.publish(document.documentId, model, {
1887
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1888
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1845
1889
  locale
1846
1890
  // TODO: Allow setting creator fields on publish
1847
1891
  // data: setCreatorFields({ user, isEdition: true })({}),
1848
1892
  });
1893
+ if (!publishResult || publishResult.length === 0) {
1894
+ throw new strapiUtils.errors.NotFoundError("Document not found or already published.");
1895
+ }
1896
+ return publishResult[0];
1849
1897
  });
1850
1898
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1851
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
1899
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1852
1900
  },
1853
1901
  async bulkPublish(ctx) {
1854
1902
  const { userAbility } = ctx.state;
1855
1903
  const { model } = ctx.params;
1856
1904
  const { body } = ctx.request;
1857
- const { ids } = body;
1905
+ const { documentIds } = body;
1858
1906
  await validateBulkActionInput(body);
1859
1907
  const documentManager2 = getService$1("document-manager");
1860
1908
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
@@ -1863,8 +1911,13 @@ const collectionTypes = {
1863
1911
  }
1864
1912
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1865
1913
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1866
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1867
- const entities = await Promise.all(entityPromises);
1914
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
1915
+ allowMultipleLocales: true
1916
+ });
1917
+ const entityPromises = documentIds.map(
1918
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1919
+ );
1920
+ const entities = (await Promise.all(entityPromises)).flat();
1868
1921
  for (const entity of entities) {
1869
1922
  if (!entity) {
1870
1923
  return ctx.notFound();
@@ -1873,24 +1926,25 @@ const collectionTypes = {
1873
1926
  return ctx.forbidden();
1874
1927
  }
1875
1928
  }
1876
- const { count } = await documentManager2.publishMany(entities, model);
1929
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1877
1930
  ctx.body = { count };
1878
1931
  },
1879
1932
  async bulkUnpublish(ctx) {
1880
1933
  const { userAbility } = ctx.state;
1881
1934
  const { model } = ctx.params;
1882
1935
  const { body } = ctx.request;
1883
- const { ids } = body;
1936
+ const { documentIds } = body;
1884
1937
  await validateBulkActionInput(body);
1885
1938
  const documentManager2 = getService$1("document-manager");
1886
1939
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1887
1940
  if (permissionChecker2.cannot.unpublish()) {
1888
1941
  return ctx.forbidden();
1889
1942
  }
1890
- const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1891
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1892
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1893
- const entities = await Promise.all(entityPromises);
1943
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1944
+ const entityPromises = documentIds.map(
1945
+ (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1946
+ );
1947
+ const entities = (await Promise.all(entityPromises)).flat();
1894
1948
  for (const entity of entities) {
1895
1949
  if (!entity) {
1896
1950
  return ctx.notFound();
@@ -1899,7 +1953,8 @@ const collectionTypes = {
1899
1953
  return ctx.forbidden();
1900
1954
  }
1901
1955
  }
1902
- const { count } = await documentManager2.unpublishMany(entities, model);
1956
+ const entitiesIds = entities.map((document) => document.documentId);
1957
+ const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
1903
1958
  ctx.body = { count };
1904
1959
  },
1905
1960
  async unpublish(ctx) {
@@ -1909,7 +1964,6 @@ const collectionTypes = {
1909
1964
  body: { discardDraft, ...body }
1910
1965
  } = ctx.request;
1911
1966
  const documentManager2 = getService$1("document-manager");
1912
- const documentMetadata2 = getService$1("document-metadata");
1913
1967
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1914
1968
  if (permissionChecker2.cannot.unpublish()) {
1915
1969
  return ctx.forbidden();
@@ -1919,7 +1973,7 @@ const collectionTypes = {
1919
1973
  }
1920
1974
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1921
1975
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1922
- const { locale } = getDocumentLocaleAndStatus(body);
1976
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1923
1977
  const document = await documentManager2.findOne(id, model, {
1924
1978
  populate,
1925
1979
  locale,
@@ -1941,7 +1995,7 @@ const collectionTypes = {
1941
1995
  ctx.body = await strapiUtils.async.pipe(
1942
1996
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1943
1997
  permissionChecker2.sanitizeOutput,
1944
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
1998
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1945
1999
  )(document);
1946
2000
  });
1947
2001
  },
@@ -1950,14 +2004,13 @@ const collectionTypes = {
1950
2004
  const { id, model } = ctx.params;
1951
2005
  const { body } = ctx.request;
1952
2006
  const documentManager2 = getService$1("document-manager");
1953
- const documentMetadata2 = getService$1("document-metadata");
1954
2007
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1955
2008
  if (permissionChecker2.cannot.discard()) {
1956
2009
  return ctx.forbidden();
1957
2010
  }
1958
2011
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1959
2012
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1960
- const { locale } = getDocumentLocaleAndStatus(body);
2013
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1961
2014
  const document = await documentManager2.findOne(id, model, {
1962
2015
  populate,
1963
2016
  locale,
@@ -1972,14 +2025,14 @@ const collectionTypes = {
1972
2025
  ctx.body = await strapiUtils.async.pipe(
1973
2026
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1974
2027
  permissionChecker2.sanitizeOutput,
1975
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2028
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1976
2029
  )(document);
1977
2030
  },
1978
2031
  async bulkDelete(ctx) {
1979
2032
  const { userAbility } = ctx.state;
1980
2033
  const { model } = ctx.params;
1981
2034
  const { query, body } = ctx.request;
1982
- const { ids } = body;
2035
+ const { documentIds } = body;
1983
2036
  await validateBulkActionInput(body);
1984
2037
  const documentManager2 = getService$1("document-manager");
1985
2038
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
@@ -1987,14 +2040,22 @@ const collectionTypes = {
1987
2040
  return ctx.forbidden();
1988
2041
  }
1989
2042
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
1990
- const idsWhereClause = { id: { $in: ids } };
1991
- const params = {
1992
- ...permissionQuery,
1993
- filters: {
1994
- $and: [idsWhereClause].concat(permissionQuery.filters || [])
2043
+ const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2044
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2045
+ const documentLocales = await documentManager2.findLocales(documentIds, model, {
2046
+ populate,
2047
+ locale
2048
+ });
2049
+ if (documentLocales.length === 0) {
2050
+ return ctx.notFound();
2051
+ }
2052
+ for (const document of documentLocales) {
2053
+ if (permissionChecker2.cannot.delete(document)) {
2054
+ return ctx.forbidden();
1995
2055
  }
1996
- };
1997
- const { count } = await documentManager2.deleteMany(params, model);
2056
+ }
2057
+ const localeDocumentsIds = documentLocales.map((document) => document.documentId);
2058
+ const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
1998
2059
  ctx.body = { count };
1999
2060
  },
2000
2061
  async countDraftRelations(ctx) {
@@ -2007,7 +2068,7 @@ const collectionTypes = {
2007
2068
  }
2008
2069
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2009
2070
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2010
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
2071
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2011
2072
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2012
2073
  if (!entity) {
2013
2074
  return ctx.notFound();
@@ -2022,7 +2083,7 @@ const collectionTypes = {
2022
2083
  },
2023
2084
  async countManyEntriesDraftRelations(ctx) {
2024
2085
  const { userAbility } = ctx.state;
2025
- const ids = ctx.request.query.ids;
2086
+ const ids = ctx.request.query.documentIds;
2026
2087
  const locale = ctx.request.query.locale;
2027
2088
  const { model } = ctx.params;
2028
2089
  const documentManager2 = getService$1("document-manager");
@@ -2030,16 +2091,16 @@ const collectionTypes = {
2030
2091
  if (permissionChecker2.cannot.read()) {
2031
2092
  return ctx.forbidden();
2032
2093
  }
2033
- const entities = await documentManager2.findMany(
2094
+ const documents = await documentManager2.findMany(
2034
2095
  {
2035
2096
  filters: {
2036
- id: ids
2097
+ documentId: ids
2037
2098
  },
2038
2099
  locale
2039
2100
  },
2040
2101
  model
2041
2102
  );
2042
- if (!entities) {
2103
+ if (!documents) {
2043
2104
  return ctx.notFound();
2044
2105
  }
2045
2106
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2535,7 +2596,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2535
2596
  throw new strapiUtils.errors.ForbiddenError();
2536
2597
  }
2537
2598
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2538
- const { locale } = getDocumentLocaleAndStatus(body);
2599
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2539
2600
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2540
2601
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2541
2602
  // Find the first document to check if it exists
@@ -2572,12 +2633,11 @@ const singleTypes = {
2572
2633
  const { model } = ctx.params;
2573
2634
  const { query = {} } = ctx.request;
2574
2635
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2575
- const documentMetadata2 = getService$1("document-metadata");
2576
2636
  if (permissionChecker2.cannot.read()) {
2577
2637
  return ctx.forbidden();
2578
2638
  }
2579
2639
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2580
- const { locale, status } = getDocumentLocaleAndStatus(query);
2640
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2581
2641
  const version = await findDocument(permissionQuery, model, { locale, status });
2582
2642
  if (!version) {
2583
2643
  if (permissionChecker2.cannot.create()) {
@@ -2587,8 +2647,10 @@ const singleTypes = {
2587
2647
  if (!document) {
2588
2648
  return ctx.notFound();
2589
2649
  }
2590
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2650
+ const { meta } = await formatDocumentWithMetadata(
2651
+ permissionChecker2,
2591
2652
  model,
2653
+ // @ts-expect-error - fix types
2592
2654
  { id: document.documentId, locale, publishedAt: null },
2593
2655
  { availableLocales: true, availableStatus: false }
2594
2656
  );
@@ -2599,16 +2661,15 @@ const singleTypes = {
2599
2661
  return ctx.forbidden();
2600
2662
  }
2601
2663
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2602
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2664
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2603
2665
  },
2604
2666
  async createOrUpdate(ctx) {
2605
2667
  const { userAbility } = ctx.state;
2606
2668
  const { model } = ctx.params;
2607
- const documentMetadata2 = getService$1("document-metadata");
2608
2669
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2609
2670
  const document = await createOrUpdateDocument(ctx);
2610
2671
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2611
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2672
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2612
2673
  },
2613
2674
  async delete(ctx) {
2614
2675
  const { userAbility } = ctx.state;
@@ -2621,7 +2682,7 @@ const singleTypes = {
2621
2682
  }
2622
2683
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2623
2684
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2624
- const { locale } = getDocumentLocaleAndStatus(query);
2685
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2625
2686
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2626
2687
  populate,
2627
2688
  locale
@@ -2644,7 +2705,6 @@ const singleTypes = {
2644
2705
  const { model } = ctx.params;
2645
2706
  const { query = {} } = ctx.request;
2646
2707
  const documentManager2 = getService$1("document-manager");
2647
- const documentMetadata2 = getService$1("document-metadata");
2648
2708
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2649
2709
  if (permissionChecker2.cannot.publish()) {
2650
2710
  return ctx.forbidden();
@@ -2659,11 +2719,12 @@ const singleTypes = {
2659
2719
  if (permissionChecker2.cannot.publish(document)) {
2660
2720
  throw new strapiUtils.errors.ForbiddenError();
2661
2721
  }
2662
- const { locale } = getDocumentLocaleAndStatus(document);
2663
- return documentManager2.publish(document.documentId, model, { locale });
2722
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2723
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2724
+ return publishResult.at(0);
2664
2725
  });
2665
2726
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2666
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2727
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2667
2728
  },
2668
2729
  async unpublish(ctx) {
2669
2730
  const { userAbility } = ctx.state;
@@ -2673,7 +2734,6 @@ const singleTypes = {
2673
2734
  query = {}
2674
2735
  } = ctx.request;
2675
2736
  const documentManager2 = getService$1("document-manager");
2676
- const documentMetadata2 = getService$1("document-metadata");
2677
2737
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2678
2738
  if (permissionChecker2.cannot.unpublish()) {
2679
2739
  return ctx.forbidden();
@@ -2682,7 +2742,7 @@ const singleTypes = {
2682
2742
  return ctx.forbidden();
2683
2743
  }
2684
2744
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2685
- const { locale } = getDocumentLocaleAndStatus(body);
2745
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2686
2746
  const document = await findDocument(sanitizedQuery, model, { locale });
2687
2747
  if (!document) {
2688
2748
  return ctx.notFound();
@@ -2700,7 +2760,7 @@ const singleTypes = {
2700
2760
  ctx.body = await strapiUtils.async.pipe(
2701
2761
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2702
2762
  permissionChecker2.sanitizeOutput,
2703
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2763
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2704
2764
  )(document);
2705
2765
  });
2706
2766
  },
@@ -2709,13 +2769,12 @@ const singleTypes = {
2709
2769
  const { model } = ctx.params;
2710
2770
  const { body, query = {} } = ctx.request;
2711
2771
  const documentManager2 = getService$1("document-manager");
2712
- const documentMetadata2 = getService$1("document-metadata");
2713
2772
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2714
2773
  if (permissionChecker2.cannot.discard()) {
2715
2774
  return ctx.forbidden();
2716
2775
  }
2717
2776
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2718
- const { locale } = getDocumentLocaleAndStatus(body);
2777
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2719
2778
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2720
2779
  if (!document) {
2721
2780
  return ctx.notFound();
@@ -2726,7 +2785,7 @@ const singleTypes = {
2726
2785
  ctx.body = await strapiUtils.async.pipe(
2727
2786
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2728
2787
  permissionChecker2.sanitizeOutput,
2729
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2788
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2730
2789
  )(document);
2731
2790
  },
2732
2791
  async countDraftRelations(ctx) {
@@ -2735,7 +2794,7 @@ const singleTypes = {
2735
2794
  const { query } = ctx.request;
2736
2795
  const documentManager2 = getService$1("document-manager");
2737
2796
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2738
- const { locale } = getDocumentLocaleAndStatus(query);
2797
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2739
2798
  if (permissionChecker2.cannot.read()) {
2740
2799
  return ctx.forbidden();
2741
2800
  }
@@ -2756,7 +2815,7 @@ const uid$1 = {
2756
2815
  async generateUID(ctx) {
2757
2816
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2758
2817
  const { query = {} } = ctx.request;
2759
- const { locale } = getDocumentLocaleAndStatus(query);
2818
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2760
2819
  await validateUIDField(contentTypeUID, field);
2761
2820
  const uidService = getService$1("uid");
2762
2821
  ctx.body = {
@@ -2768,7 +2827,7 @@ const uid$1 = {
2768
2827
  ctx.request.body
2769
2828
  );
2770
2829
  const { query = {} } = ctx.request;
2771
- const { locale } = getDocumentLocaleAndStatus(query);
2830
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2772
2831
  await validateUIDField(contentTypeUID, field);
2773
2832
  const uidService = getService$1("uid");
2774
2833
  const isAvailable = await uidService.checkUIDAvailability({
@@ -3559,7 +3618,7 @@ const permission = ({ strapi: strapi2 }) => ({
3559
3618
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3560
3619
  }
3561
3620
  });
3562
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils__default.default.contentTypes;
3621
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils__default.default.contentTypes;
3563
3622
  const { isAnyToMany } = strapiUtils__default.default.relations;
3564
3623
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils__default.default.contentTypes.constants;
3565
3624
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3650,6 +3709,42 @@ const getDeepPopulate = (uid2, {
3650
3709
  {}
3651
3710
  );
3652
3711
  };
3712
+ const getValidatableFieldsPopulate = (uid2, {
3713
+ initialPopulate = {},
3714
+ countMany = false,
3715
+ countOne = false,
3716
+ maxLevel = Infinity
3717
+ } = {}, level = 1) => {
3718
+ if (level > maxLevel) {
3719
+ return {};
3720
+ }
3721
+ const model = strapi.getModel(uid2);
3722
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3723
+ if (!getDoesAttributeRequireValidation(attribute)) {
3724
+ return populateAcc;
3725
+ }
3726
+ if (isScalarAttribute(attribute)) {
3727
+ return fp.merge(populateAcc, {
3728
+ [attributeName]: true
3729
+ });
3730
+ }
3731
+ return fp.merge(
3732
+ populateAcc,
3733
+ getPopulateFor(
3734
+ attributeName,
3735
+ model,
3736
+ {
3737
+ // @ts-expect-error - improve types
3738
+ initialPopulate: initialPopulate?.[attributeName],
3739
+ countMany,
3740
+ countOne,
3741
+ maxLevel
3742
+ },
3743
+ level
3744
+ )
3745
+ );
3746
+ }, {});
3747
+ };
3653
3748
  const getDeepPopulateDraftCount = (uid2) => {
3654
3749
  const model = strapi.getModel(uid2);
3655
3750
  let hasRelations = false;
@@ -3657,6 +3752,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3657
3752
  const attribute = model.attributes[attributeName];
3658
3753
  switch (attribute.type) {
3659
3754
  case "relation": {
3755
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
3756
+ if (isMorphRelation) {
3757
+ break;
3758
+ }
3660
3759
  if (isVisibleAttribute$1(model, attributeName)) {
3661
3760
  populateAcc[attributeName] = {
3662
3761
  count: true,
@@ -3671,22 +3770,24 @@ const getDeepPopulateDraftCount = (uid2) => {
3671
3770
  attribute.component
3672
3771
  );
3673
3772
  if (childHasRelations) {
3674
- populateAcc[attributeName] = { populate: populate2 };
3773
+ populateAcc[attributeName] = {
3774
+ populate: populate2
3775
+ };
3675
3776
  hasRelations = true;
3676
3777
  }
3677
3778
  break;
3678
3779
  }
3679
3780
  case "dynamiczone": {
3680
- const dzPopulate = (attribute.components || []).reduce((acc, componentUID) => {
3681
- const { populate: populate2, hasRelations: childHasRelations } = getDeepPopulateDraftCount(componentUID);
3682
- if (childHasRelations) {
3781
+ const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
3782
+ const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
3783
+ if (componentHasRelations) {
3683
3784
  hasRelations = true;
3684
- return fp.merge(acc, populate2);
3785
+ return { ...acc, [componentUID]: { populate: componentPopulate } };
3685
3786
  }
3686
3787
  return acc;
3687
3788
  }, {});
3688
- if (!fp.isEmpty(dzPopulate)) {
3689
- populateAcc[attributeName] = { populate: dzPopulate };
3789
+ if (!fp.isEmpty(dzPopulateFragment)) {
3790
+ populateAcc[attributeName] = { on: dzPopulateFragment };
3690
3791
  }
3691
3792
  break;
3692
3793
  }
@@ -3878,41 +3979,70 @@ const AVAILABLE_STATUS_FIELDS = [
3878
3979
  "updatedBy",
3879
3980
  "status"
3880
3981
  ];
3881
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
3982
+ const AVAILABLE_LOCALES_FIELDS = [
3983
+ "id",
3984
+ "locale",
3985
+ "updatedAt",
3986
+ "createdAt",
3987
+ "status",
3988
+ "publishedAt",
3989
+ "documentId"
3990
+ ];
3882
3991
  const CONTENT_MANAGER_STATUS = {
3883
3992
  PUBLISHED: "published",
3884
3993
  DRAFT: "draft",
3885
3994
  MODIFIED: "modified"
3886
3995
  };
3887
- const areDatesEqual = (date1, date2, threshold) => {
3888
- if (!date1 || !date2) {
3996
+ const getIsVersionLatestModification = (version, otherVersion) => {
3997
+ if (!version || !version.updatedAt) {
3889
3998
  return false;
3890
3999
  }
3891
- const time1 = new Date(date1).getTime();
3892
- const time2 = new Date(date2).getTime();
3893
- const difference = Math.abs(time1 - time2);
3894
- return difference <= threshold;
4000
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
4001
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
4002
+ return versionUpdatedAt > otherUpdatedAt;
3895
4003
  };
3896
4004
  const documentMetadata = ({ strapi: strapi2 }) => ({
3897
4005
  /**
3898
4006
  * Returns available locales of a document for the current status
3899
4007
  */
3900
- getAvailableLocales(uid2, version, allVersions) {
4008
+ async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
3901
4009
  const versionsByLocale = fp.groupBy("locale", allVersions);
3902
4010
  delete versionsByLocale[version.locale];
3903
- return Object.values(versionsByLocale).map((localeVersions) => {
3904
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2))) {
3905
- return fp.pick(AVAILABLE_LOCALES_FIELDS, localeVersions[0]);
4011
+ const model = strapi2.getModel(uid2);
4012
+ const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
4013
+ const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
4014
+ ({ key }, { remove }) => {
4015
+ if (keysToKeep.includes(key)) {
4016
+ return;
4017
+ }
4018
+ remove(key);
4019
+ },
4020
+ { schema: model, getModel: strapi2.getModel.bind(strapi2) },
4021
+ // @ts-expect-error fix types DocumentVersion incompatible with Data
4022
+ localeVersion
4023
+ );
4024
+ const mappingResult = await strapiUtils.async.map(
4025
+ Object.values(versionsByLocale),
4026
+ async (localeVersions) => {
4027
+ const mappedLocaleVersions = await strapiUtils.async.map(
4028
+ localeVersions,
4029
+ traversalFunction
4030
+ );
4031
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
4032
+ return mappedLocaleVersions[0];
4033
+ }
4034
+ const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4035
+ const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
4036
+ if (!draftVersion) {
4037
+ return;
4038
+ }
4039
+ return {
4040
+ ...draftVersion,
4041
+ status: this.getStatus(draftVersion, otherVersions)
4042
+ };
3906
4043
  }
3907
- const draftVersion = localeVersions.find((v) => v.publishedAt === null);
3908
- const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
3909
- if (!draftVersion)
3910
- return;
3911
- return {
3912
- ...fp.pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
3913
- status: this.getStatus(draftVersion, otherVersions)
3914
- };
3915
- }).filter(Boolean);
4044
+ );
4045
+ return mappingResult.filter(Boolean);
3916
4046
  },
3917
4047
  /**
3918
4048
  * Returns available status of a document for the current locale
@@ -3950,26 +4080,37 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3950
4080
  });
3951
4081
  },
3952
4082
  getStatus(version, otherDocumentStatuses) {
3953
- const isDraft = version.publishedAt === null;
3954
- if (!otherDocumentStatuses?.length) {
3955
- return isDraft ? CONTENT_MANAGER_STATUS.DRAFT : CONTENT_MANAGER_STATUS.PUBLISHED;
4083
+ let draftVersion;
4084
+ let publishedVersion;
4085
+ if (version.publishedAt) {
4086
+ publishedVersion = version;
4087
+ } else {
4088
+ draftVersion = version;
3956
4089
  }
3957
- if (isDraft) {
3958
- const publishedVersion = otherDocumentStatuses?.find((d) => d.publishedAt !== null);
3959
- if (!publishedVersion) {
3960
- return CONTENT_MANAGER_STATUS.DRAFT;
3961
- }
4090
+ const otherVersion = otherDocumentStatuses?.at(0);
4091
+ if (otherVersion?.publishedAt) {
4092
+ publishedVersion = otherVersion;
4093
+ } else if (otherVersion) {
4094
+ draftVersion = otherVersion;
3962
4095
  }
3963
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
4096
+ if (!draftVersion)
3964
4097
  return CONTENT_MANAGER_STATUS.PUBLISHED;
3965
- }
3966
- return CONTENT_MANAGER_STATUS.MODIFIED;
4098
+ if (!publishedVersion)
4099
+ return CONTENT_MANAGER_STATUS.DRAFT;
4100
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4101
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3967
4102
  },
4103
+ // TODO is it necessary to return metadata on every page of the CM
4104
+ // We could refactor this so the locales are only loaded when they're
4105
+ // needed. e.g. in the bulk locale action modal.
3968
4106
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4107
+ const populate = getValidatableFieldsPopulate(uid2);
3969
4108
  const versions = await strapi2.db.query(uid2).findMany({
3970
4109
  where: { documentId: version.documentId },
3971
- select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
3972
4110
  populate: {
4111
+ // Populate only fields that require validation for bulk locale actions
4112
+ ...populate,
4113
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3973
4114
  createdBy: {
3974
4115
  select: ["id", "firstname", "lastname", "email"]
3975
4116
  },
@@ -3978,7 +4119,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3978
4119
  }
3979
4120
  }
3980
4121
  });
3981
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
4122
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
3982
4123
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3983
4124
  return {
3984
4125
  availableLocales: availableLocalesResult,
@@ -3991,8 +4132,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3991
4132
  * - Available status of the document for the current locale
3992
4133
  */
3993
4134
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3994
- if (!document)
4135
+ if (!document) {
3995
4136
  return document;
4137
+ }
3996
4138
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
3997
4139
  if (!hasDraftAndPublish) {
3998
4140
  opts.availableStatus = false;
@@ -4042,26 +4184,9 @@ const sumDraftCounts = (entity, uid2) => {
4042
4184
  }, 0);
4043
4185
  };
4044
4186
  const { ApplicationError } = strapiUtils.errors;
4045
- const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
4046
4187
  const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
4047
4188
  const omitPublishedAtField = fp.omit(PUBLISHED_AT_ATTRIBUTE);
4048
4189
  const omitIdField = fp.omit("id");
4049
- const emitEvent = async (uid2, event, document) => {
4050
- const modelDef = strapi.getModel(uid2);
4051
- const sanitizedDocument = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
4052
- {
4053
- schema: modelDef,
4054
- getModel(uid22) {
4055
- return strapi.getModel(uid22);
4056
- }
4057
- },
4058
- document
4059
- );
4060
- strapi.eventHub.emit(event, {
4061
- model: modelDef.modelName,
4062
- entry: sanitizedDocument
4063
- });
4064
- };
4065
4190
  const documentManager = ({ strapi: strapi2 }) => {
4066
4191
  return {
4067
4192
  async findOne(id, uid2, opts = {}) {
@@ -4080,6 +4205,9 @@ const documentManager = ({ strapi: strapi2 }) => {
4080
4205
  } else if (opts.locale && opts.locale !== "*") {
4081
4206
  where.locale = opts.locale;
4082
4207
  }
4208
+ if (typeof opts.isPublished === "boolean") {
4209
+ where.publishedAt = { $notNull: opts.isPublished };
4210
+ }
4083
4211
  return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
4084
4212
  },
4085
4213
  async findMany(opts, uid2) {
@@ -4087,20 +4215,16 @@ const documentManager = ({ strapi: strapi2 }) => {
4087
4215
  return strapi2.documents(uid2).findMany(params);
4088
4216
  },
4089
4217
  async findPage(opts, uid2) {
4090
- const page = Number(opts?.page) || 1;
4091
- const pageSize = Number(opts?.pageSize) || 10;
4218
+ const params = strapiUtils.pagination.withDefaultPagination(opts || {}, {
4219
+ maxLimit: 1e3
4220
+ });
4092
4221
  const [documents, total = 0] = await Promise.all([
4093
- strapi2.documents(uid2).findMany(opts),
4094
- strapi2.documents(uid2).count(opts)
4222
+ strapi2.documents(uid2).findMany(params),
4223
+ strapi2.documents(uid2).count(params)
4095
4224
  ]);
4096
4225
  return {
4097
4226
  results: documents,
4098
- pagination: {
4099
- page,
4100
- pageSize,
4101
- pageCount: Math.ceil(total / pageSize),
4102
- total
4103
- }
4227
+ pagination: strapiUtils.pagination.transformPagedPaginationInfo(params, total)
4104
4228
  };
4105
4229
  },
4106
4230
  async create(uid2, opts = {}) {
@@ -4117,10 +4241,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4117
4241
  async clone(id, body, uid2) {
4118
4242
  const populate = await buildDeepPopulate(uid2);
4119
4243
  const params = {
4120
- data: {
4121
- ...omitIdField(body),
4122
- [PUBLISHED_AT_ATTRIBUTE]: null
4123
- },
4244
+ data: omitIdField(body),
4124
4245
  populate
4125
4246
  };
4126
4247
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4146,70 +4267,36 @@ const documentManager = ({ strapi: strapi2 }) => {
4146
4267
  return {};
4147
4268
  },
4148
4269
  // FIXME: handle relations
4149
- async deleteMany(opts, uid2) {
4150
- const docs = await strapi2.documents(uid2).findMany(opts);
4151
- for (const doc of docs) {
4152
- await strapi2.documents(uid2).delete({ documentId: doc.documentId });
4153
- }
4154
- return { count: docs.length };
4270
+ async deleteMany(documentIds, uid2, opts = {}) {
4271
+ const deletedEntries = await strapi2.db.transaction(async () => {
4272
+ return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4273
+ });
4274
+ return { count: deletedEntries.length };
4155
4275
  },
4156
4276
  async publish(id, uid2, opts = {}) {
4157
4277
  const populate = await buildDeepPopulate(uid2);
4158
4278
  const params = { ...opts, populate };
4159
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4279
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4160
4280
  },
4161
- async publishMany(entities, uid2) {
4162
- if (!entities.length) {
4163
- return null;
4164
- }
4165
- await Promise.all(
4166
- entities.map((document) => {
4167
- return strapi2.entityValidator.validateEntityCreation(
4168
- strapi2.getModel(uid2),
4169
- document,
4170
- void 0,
4171
- // @ts-expect-error - FIXME: entity here is unnecessary
4172
- document
4173
- );
4174
- })
4175
- );
4176
- const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4177
- const filters = { id: { $in: entitiesToPublish } };
4178
- const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
4179
- const populate = await buildDeepPopulate(uid2);
4180
- const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4181
- where: filters,
4182
- data
4183
- });
4184
- const publishedEntities = await strapi2.db.query(uid2).findMany({
4185
- where: filters,
4186
- populate
4281
+ async publishMany(uid2, documentIds, locale) {
4282
+ return strapi2.db.transaction(async () => {
4283
+ const results = await Promise.all(
4284
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4285
+ );
4286
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4287
+ return publishedEntitiesCount;
4187
4288
  });
4188
- await Promise.all(
4189
- publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
4190
- );
4191
- return publishedEntitiesCount;
4192
4289
  },
4193
- async unpublishMany(documents, uid2) {
4194
- if (!documents.length) {
4195
- return null;
4196
- }
4197
- const entitiesToUnpublish = documents.filter((doc) => doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4198
- const filters = { id: { $in: entitiesToUnpublish } };
4199
- const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
4200
- const populate = await buildDeepPopulate(uid2);
4201
- const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4202
- where: filters,
4203
- data
4204
- });
4205
- const unpublishedEntities = await strapi2.db.query(uid2).findMany({
4206
- where: filters,
4207
- populate
4290
+ async unpublishMany(documentIds, uid2, opts = {}) {
4291
+ const unpublishedEntries = await strapi2.db.transaction(async () => {
4292
+ return Promise.all(
4293
+ documentIds.map(
4294
+ (id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
4295
+ )
4296
+ );
4208
4297
  });
4209
- await Promise.all(
4210
- unpublishedEntities.map((doc) => emitEvent(uid2, ENTRY_UNPUBLISH, doc))
4211
- );
4212
- return unpublishedEntitiesCount;
4298
+ const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
4299
+ return { count: unpublishedEntitiesCount };
4213
4300
  },
4214
4301
  async unpublish(id, uid2, opts = {}) {
4215
4302
  const populate = await buildDeepPopulate(uid2);
@@ -4234,16 +4321,20 @@ const documentManager = ({ strapi: strapi2 }) => {
4234
4321
  }
4235
4322
  return sumDraftCounts(document, uid2);
4236
4323
  },
4237
- async countManyEntriesDraftRelations(ids, uid2, locale) {
4324
+ async countManyEntriesDraftRelations(documentIds, uid2, locale) {
4238
4325
  const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
4239
4326
  if (!hasRelations) {
4240
4327
  return 0;
4241
4328
  }
4329
+ let localeFilter = {};
4330
+ if (locale) {
4331
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4332
+ }
4242
4333
  const entities = await strapi2.db.query(uid2).findMany({
4243
4334
  populate,
4244
4335
  where: {
4245
- id: { $in: ids },
4246
- ...locale ? { locale } : {}
4336
+ documentId: { $in: documentIds },
4337
+ ...localeFilter
4247
4338
  }
4248
4339
  });
4249
4340
  const totalNumberDraftRelations = entities.reduce(