@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.25e22c6cc9bc6b35392bb55d09f641a0a65e7403

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