@strapi/content-manager 0.0.0-experimental.826f263c58b6886b849d3f03b81f7a530bc51c91 → 0.0.0-experimental.82afe56cecefd0078d534e25909834ecf5fdd404

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 (231) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  3. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js → ComponentConfigurationPage-DMxUlNOo.js} +5 -6
  5. package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js.map → ComponentConfigurationPage-DMxUlNOo.js.map} +1 -1
  6. package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs → ComponentConfigurationPage-baEkO-OV.mjs} +4 -4
  7. package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs.map → ComponentConfigurationPage-baEkO-OV.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  9. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  10. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  11. package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js → EditConfigurationPage-CXxV7mKn.js} +5 -6
  12. package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js.map → EditConfigurationPage-CXxV7mKn.js.map} +1 -1
  13. package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs → EditConfigurationPage-YR8-4VCS.mjs} +4 -4
  14. package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs.map → EditConfigurationPage-YR8-4VCS.mjs.map} +1 -1
  15. package/dist/_chunks/{EditViewPage-CoQEnFlC.js → EditViewPage-BfR6jAR6.js} +71 -84
  16. package/dist/_chunks/EditViewPage-BfR6jAR6.js.map +1 -0
  17. package/dist/_chunks/EditViewPage-DFF7c27p.mjs +191 -0
  18. package/dist/_chunks/EditViewPage-DFF7c27p.mjs.map +1 -0
  19. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  20. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  21. package/dist/_chunks/{Form-Bpig5rch.js → Form-CjcMRP5A.js} +55 -38
  22. package/dist/_chunks/Form-CjcMRP5A.js.map +1 -0
  23. package/dist/_chunks/{Form-Dxmihyw8.mjs → Form-MSOSfGGN.mjs} +55 -37
  24. package/dist/_chunks/Form-MSOSfGGN.mjs.map +1 -0
  25. package/dist/_chunks/{History-BfX6XmZK.js → History-BgZ7gVuF.js} +208 -138
  26. package/dist/_chunks/History-BgZ7gVuF.js.map +1 -0
  27. package/dist/_chunks/{History-BZP8n7KT.mjs → History-WOQNVho-.mjs} +201 -130
  28. package/dist/_chunks/History-WOQNVho-.mjs.map +1 -0
  29. package/dist/_chunks/{Field-Cz_J9551.mjs → Input-BkKwZ6Qt.mjs} +1757 -1383
  30. package/dist/_chunks/Input-BkKwZ6Qt.mjs.map +1 -0
  31. package/dist/_chunks/{Field-ZdrmmQ4Y.js → Input-BwOibhc3.js} +1748 -1374
  32. package/dist/_chunks/Input-BwOibhc3.js.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-DxKuVkKz.mjs → ListConfigurationPage-BeXfr6uW.mjs} +63 -52
  34. package/dist/_chunks/ListConfigurationPage-BeXfr6uW.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-B3CXj8PY.js → ListConfigurationPage-DnJ3nbwL.js} +62 -51
  36. package/dist/_chunks/ListConfigurationPage-DnJ3nbwL.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-Bk9VO__I.js → ListViewPage-CJFDudKl.js} +155 -129
  38. package/dist/_chunks/ListViewPage-CJFDudKl.js.map +1 -0
  39. package/dist/_chunks/{ListViewPage-D5D3tVPq.mjs → ListViewPage-VK2v44Q1.mjs} +156 -129
  40. package/dist/_chunks/ListViewPage-VK2v44Q1.mjs.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs → NoContentTypePage-T8ttty6K.mjs} +2 -2
  42. package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs.map → NoContentTypePage-T8ttty6K.mjs.map} +1 -1
  43. package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js → NoContentTypePage-en2PwWgI.js} +2 -2
  44. package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js.map → NoContentTypePage-en2PwWgI.js.map} +1 -1
  45. package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js → NoPermissionsPage-CcjILry3.js} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js.map → NoPermissionsPage-CcjILry3.js.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs → NoPermissionsPage-CokBHhhy.mjs} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs.map → NoPermissionsPage-CokBHhhy.mjs.map} +1 -1
  49. package/dist/_chunks/Preview-BF81YhRj.mjs +287 -0
  50. package/dist/_chunks/Preview-BF81YhRj.mjs.map +1 -0
  51. package/dist/_chunks/Preview-DgzAuzWQ.js +305 -0
  52. package/dist/_chunks/Preview-DgzAuzWQ.js.map +1 -0
  53. package/dist/_chunks/{Relations-B6B3A3mb.js → Relations-1O-JcM4t.js} +76 -43
  54. package/dist/_chunks/Relations-1O-JcM4t.js.map +1 -0
  55. package/dist/_chunks/{Relations-BOYZmuWy.mjs → Relations-BncdhGCd.mjs} +76 -42
  56. package/dist/_chunks/Relations-BncdhGCd.mjs.map +1 -0
  57. package/dist/_chunks/{en-Dzv55oQw.mjs → en-BZaUty0m.mjs} +41 -18
  58. package/dist/_chunks/{en-Dzv55oQw.mjs.map → en-BZaUty0m.mjs.map} +1 -1
  59. package/dist/_chunks/{en-BN1bvFK7.js → en-CzCnBk4S.js} +41 -18
  60. package/dist/_chunks/{en-BN1bvFK7.js.map → en-CzCnBk4S.js.map} +1 -1
  61. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  62. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  63. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  64. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  65. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  66. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  67. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  68. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  69. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  70. package/dist/_chunks/{index-VHviNMeW.mjs → index-DiluOUp6.mjs} +1469 -966
  71. package/dist/_chunks/index-DiluOUp6.mjs.map +1 -0
  72. package/dist/_chunks/{index-DzN3kBgx.js → index-EXJvmn4t.js} +1439 -936
  73. package/dist/_chunks/index-EXJvmn4t.js.map +1 -0
  74. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  75. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  77. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  78. package/dist/_chunks/{layout-b91XRlD2.js → layout-4TbKVax8.js} +41 -24
  79. package/dist/_chunks/layout-4TbKVax8.js.map +1 -0
  80. package/dist/_chunks/{layout-CPn1PM6x.mjs → layout-mSwsYzxv.mjs} +42 -24
  81. package/dist/_chunks/layout-mSwsYzxv.mjs.map +1 -0
  82. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  83. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  84. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  85. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  86. package/dist/_chunks/{relations-BsqxS6tR.mjs → relations--YOvQBqv.mjs} +6 -7
  87. package/dist/_chunks/relations--YOvQBqv.mjs.map +1 -0
  88. package/dist/_chunks/{relations-CA7IYmcP.js → relations-Ai6Izh7h.js} +6 -7
  89. package/dist/_chunks/relations-Ai6Izh7h.js.map +1 -0
  90. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  91. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  92. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  93. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  94. package/dist/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
  95. package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
  96. package/dist/_chunks/{usePrev-B9w_-eYc.js → usePrev-D5J_2fEu.js} +14 -1
  97. package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
  98. package/dist/admin/index.js +3 -1
  99. package/dist/admin/index.js.map +1 -1
  100. package/dist/admin/index.mjs +10 -8
  101. package/dist/admin/src/content-manager.d.ts +3 -2
  102. package/dist/admin/src/exports.d.ts +2 -1
  103. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  104. package/dist/admin/src/history/index.d.ts +3 -0
  105. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  106. package/dist/admin/src/hooks/useDocument.d.ts +49 -1
  107. package/dist/admin/src/index.d.ts +1 -0
  108. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  109. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +9 -4
  110. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  111. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  112. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  113. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +5 -0
  114. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  115. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  116. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  117. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  118. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  119. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  120. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  121. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  122. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  123. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  124. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  125. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  126. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  127. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  128. package/dist/admin/src/preview/index.d.ts +4 -0
  129. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  130. package/dist/admin/src/preview/routes.d.ts +3 -0
  131. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  132. package/dist/admin/src/router.d.ts +1 -1
  133. package/dist/admin/src/services/api.d.ts +1 -1
  134. package/dist/admin/src/services/components.d.ts +2 -2
  135. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  136. package/dist/admin/src/services/documents.d.ts +19 -20
  137. package/dist/admin/src/services/init.d.ts +1 -1
  138. package/dist/admin/src/services/relations.d.ts +2 -2
  139. package/dist/admin/src/services/uid.d.ts +3 -3
  140. package/dist/admin/src/utils/validation.d.ts +4 -1
  141. package/dist/server/index.js +765 -434
  142. package/dist/server/index.js.map +1 -1
  143. package/dist/server/index.mjs +766 -434
  144. package/dist/server/index.mjs.map +1 -1
  145. package/dist/server/src/bootstrap.d.ts.map +1 -1
  146. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  147. package/dist/server/src/controllers/index.d.ts.map +1 -1
  148. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  149. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  150. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  151. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  152. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  153. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  154. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  155. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  156. package/dist/server/src/history/services/history.d.ts +3 -3
  157. package/dist/server/src/history/services/history.d.ts.map +1 -1
  158. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  159. package/dist/server/src/history/services/utils.d.ts +8 -12
  160. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  161. package/dist/server/src/index.d.ts +7 -6
  162. package/dist/server/src/index.d.ts.map +1 -1
  163. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  164. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  165. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  166. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  167. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  168. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  169. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  170. package/dist/server/src/preview/index.d.ts +4 -0
  171. package/dist/server/src/preview/index.d.ts.map +1 -0
  172. package/dist/server/src/preview/routes/index.d.ts +8 -0
  173. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  174. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  175. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  176. package/dist/server/src/preview/services/index.d.ts +16 -0
  177. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  178. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  179. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  180. package/dist/server/src/preview/services/preview.d.ts +12 -0
  181. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  182. package/dist/server/src/preview/utils.d.ts +19 -0
  183. package/dist/server/src/preview/utils.d.ts.map +1 -0
  184. package/dist/server/src/register.d.ts.map +1 -1
  185. package/dist/server/src/routes/index.d.ts.map +1 -1
  186. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  187. package/dist/server/src/services/document-metadata.d.ts +12 -10
  188. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  189. package/dist/server/src/services/index.d.ts +7 -6
  190. package/dist/server/src/services/index.d.ts.map +1 -1
  191. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  192. package/dist/server/src/services/utils/populate.d.ts +2 -2
  193. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  194. package/dist/server/src/utils/index.d.ts +2 -0
  195. package/dist/server/src/utils/index.d.ts.map +1 -1
  196. package/dist/shared/contracts/collection-types.d.ts +3 -1
  197. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  198. package/dist/shared/contracts/index.d.ts +1 -0
  199. package/dist/shared/contracts/index.d.ts.map +1 -1
  200. package/dist/shared/contracts/preview.d.ts +27 -0
  201. package/dist/shared/contracts/preview.d.ts.map +1 -0
  202. package/dist/shared/index.js +4 -0
  203. package/dist/shared/index.js.map +1 -1
  204. package/dist/shared/index.mjs +4 -0
  205. package/dist/shared/index.mjs.map +1 -1
  206. package/package.json +17 -16
  207. package/dist/_chunks/EditViewPage-CoQEnFlC.js.map +0 -1
  208. package/dist/_chunks/EditViewPage-DvaV7U9b.mjs +0 -203
  209. package/dist/_chunks/EditViewPage-DvaV7U9b.mjs.map +0 -1
  210. package/dist/_chunks/Field-Cz_J9551.mjs.map +0 -1
  211. package/dist/_chunks/Field-ZdrmmQ4Y.js.map +0 -1
  212. package/dist/_chunks/Form-Bpig5rch.js.map +0 -1
  213. package/dist/_chunks/Form-Dxmihyw8.mjs.map +0 -1
  214. package/dist/_chunks/History-BZP8n7KT.mjs.map +0 -1
  215. package/dist/_chunks/History-BfX6XmZK.js.map +0 -1
  216. package/dist/_chunks/ListConfigurationPage-B3CXj8PY.js.map +0 -1
  217. package/dist/_chunks/ListConfigurationPage-DxKuVkKz.mjs.map +0 -1
  218. package/dist/_chunks/ListViewPage-Bk9VO__I.js.map +0 -1
  219. package/dist/_chunks/ListViewPage-D5D3tVPq.mjs.map +0 -1
  220. package/dist/_chunks/Relations-B6B3A3mb.js.map +0 -1
  221. package/dist/_chunks/Relations-BOYZmuWy.mjs.map +0 -1
  222. package/dist/_chunks/index-DzN3kBgx.js.map +0 -1
  223. package/dist/_chunks/index-VHviNMeW.mjs.map +0 -1
  224. package/dist/_chunks/layout-CPn1PM6x.mjs.map +0 -1
  225. package/dist/_chunks/layout-b91XRlD2.js.map +0 -1
  226. package/dist/_chunks/relations-BsqxS6tR.mjs.map +0 -1
  227. package/dist/_chunks/relations-CA7IYmcP.js.map +0 -1
  228. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  229. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  230. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  231. package/strapi-server.js +0 -3
@@ -10,8 +10,7 @@ const qs = require("qs");
10
10
  const slugify = require("@sindresorhus/slugify");
11
11
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
12
  function _interopNamespace(e) {
13
- if (e && e.__esModule)
14
- return e;
13
+ if (e && e.__esModule) return e;
15
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
16
15
  if (e) {
17
16
  for (const k in e) {
@@ -33,10 +32,10 @@ const isNil__default = /* @__PURE__ */ _interopDefault(isNil);
33
32
  const ___default = /* @__PURE__ */ _interopDefault(_);
34
33
  const qs__default = /* @__PURE__ */ _interopDefault(qs);
35
34
  const slugify__default = /* @__PURE__ */ _interopDefault(slugify);
36
- const getService$1 = (name) => {
35
+ const getService$2 = (name) => {
37
36
  return strapi.plugin("content-manager").service(name);
38
37
  };
39
- function getService(strapi2, name) {
38
+ function getService$1(strapi2, name) {
40
39
  return strapi2.service(`plugin::content-manager.${name}`);
41
40
  }
42
41
  const historyRestoreVersionSchema = yup__namespace.object().shape({
@@ -72,7 +71,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
72
71
  if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
73
72
  throw new strapiUtils.errors.ForbiddenError("contentType and documentId are required");
74
73
  }
75
- const permissionChecker2 = getService$1("permission-checker").create({
74
+ const permissionChecker2 = getService$2("permission-checker").create({
76
75
  userAbility: ctx.state.userAbility,
77
76
  model: ctx.query.contentType
78
77
  });
@@ -80,7 +79,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
80
79
  return ctx.forbidden();
81
80
  }
82
81
  const query = await permissionChecker2.sanitizeQuery(ctx.query);
83
- const { results, pagination } = await getService(strapi2, "history").findVersionsPage({
82
+ const { results, pagination } = await getService$1(strapi2, "history").findVersionsPage({
84
83
  query: {
85
84
  ...query,
86
85
  ...getValidPagination({ page: query.page, pageSize: query.pageSize })
@@ -105,14 +104,14 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
105
104
  async restoreVersion(ctx) {
106
105
  const request = ctx.request;
107
106
  await validateRestoreVersion(request.body, "contentType is required");
108
- const permissionChecker2 = getService$1("permission-checker").create({
107
+ const permissionChecker2 = getService$2("permission-checker").create({
109
108
  userAbility: ctx.state.userAbility,
110
109
  model: request.body.contentType
111
110
  });
112
111
  if (permissionChecker2.cannot.update()) {
113
112
  throw new strapiUtils.errors.ForbiddenError();
114
113
  }
115
- const restoredDocument = await getService(strapi2, "history").restoreVersion(
114
+ const restoredDocument = await getService$1(strapi2, "history").restoreVersion(
116
115
  request.params.versionId
117
116
  );
118
117
  return {
@@ -121,7 +120,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
121
120
  }
122
121
  };
123
122
  };
124
- const controllers$1 = {
123
+ const controllers$2 = {
125
124
  "history-version": createHistoryVersionController
126
125
  /**
127
126
  * Casting is needed because the types aren't aware that Strapi supports
@@ -167,8 +166,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
167
166
  };
168
167
  const getRelationRestoreValue = async (versionRelationData, attribute) => {
169
168
  if (Array.isArray(versionRelationData)) {
170
- if (versionRelationData.length === 0)
171
- return versionRelationData;
169
+ if (versionRelationData.length === 0) return versionRelationData;
172
170
  const existingAndMissingRelations = await Promise.all(
173
171
  versionRelationData.map((relation) => {
174
172
  return strapi2.documents(attribute.target).findOne({
@@ -177,19 +175,16 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
177
175
  });
178
176
  })
179
177
  );
180
- return existingAndMissingRelations.filter(
181
- (relation) => relation !== null
182
- );
178
+ return existingAndMissingRelations.filter((relation) => relation !== null);
183
179
  }
184
180
  return strapi2.documents(attribute.target).findOne({
185
181
  documentId: versionRelationData.documentId,
186
182
  locale: versionRelationData.locale || void 0
187
183
  });
188
184
  };
189
- const getMediaRestoreValue = async (versionRelationData, attribute) => {
190
- if (attribute.multiple) {
185
+ const getMediaRestoreValue = async (versionRelationData) => {
186
+ if (Array.isArray(versionRelationData)) {
191
187
  const existingAndMissingMedias = await Promise.all(
192
- // @ts-expect-error Fix the type definitions so this isn't any
193
188
  versionRelationData.map((media) => {
194
189
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
195
190
  })
@@ -199,10 +194,11 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
199
194
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
200
195
  };
201
196
  const localesService = strapi2.plugin("i18n")?.service("locales");
197
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
202
198
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
199
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
203
200
  const getLocaleDictionary = async () => {
204
- if (!localesService)
205
- return {};
201
+ if (!localesService) return {};
206
202
  const locales = await localesService.find() || [];
207
203
  return locales.reduce(
208
204
  (acc, locale) => {
@@ -226,31 +222,53 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
226
222
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
227
223
  return documentMetadataService.getStatus(document, meta.availableStatus);
228
224
  };
229
- const getDeepPopulate2 = (uid2) => {
225
+ const getComponentFields = (componentUID) => {
226
+ return Object.entries(strapi2.getModel(componentUID).attributes).reduce(
227
+ (fieldsAcc, [key, attribute]) => {
228
+ if (!["relation", "media", "component", "dynamiczone"].includes(attribute.type)) {
229
+ fieldsAcc.push(key);
230
+ }
231
+ return fieldsAcc;
232
+ },
233
+ []
234
+ );
235
+ };
236
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
230
237
  const model = strapi2.getModel(uid2);
231
238
  const attributes = Object.entries(model.attributes);
239
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
232
240
  return attributes.reduce((acc, [attributeName, attribute]) => {
233
241
  switch (attribute.type) {
234
242
  case "relation": {
243
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
244
+ if (isMorphRelation) {
245
+ break;
246
+ }
235
247
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
236
248
  if (isVisible2) {
237
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
249
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
238
250
  }
239
251
  break;
240
252
  }
241
253
  case "media": {
242
- acc[attributeName] = { fields: ["id"] };
254
+ acc[attributeName] = { [fieldSelector]: ["id"] };
243
255
  break;
244
256
  }
245
257
  case "component": {
246
258
  const populate = getDeepPopulate2(attribute.component);
247
- acc[attributeName] = { populate };
259
+ acc[attributeName] = {
260
+ populate,
261
+ [fieldSelector]: getComponentFields(attribute.component)
262
+ };
248
263
  break;
249
264
  }
250
265
  case "dynamiczone": {
251
266
  const populatedComponents = (attribute.components || []).reduce(
252
267
  (acc2, componentUID) => {
253
- acc2[componentUID] = { populate: getDeepPopulate2(componentUID) };
268
+ acc2[componentUID] = {
269
+ populate: getDeepPopulate2(componentUID),
270
+ [fieldSelector]: getComponentFields(componentUID)
271
+ };
254
272
  return acc2;
255
273
  },
256
274
  {}
@@ -312,6 +330,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
312
330
  getRelationRestoreValue,
313
331
  getMediaRestoreValue,
314
332
  getDefaultLocale,
333
+ isLocalizedContentType,
315
334
  getLocaleDictionary,
316
335
  getRetentionDays,
317
336
  getVersionStatus,
@@ -334,7 +353,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
334
353
  });
335
354
  },
336
355
  async findVersionsPage(params) {
337
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
356
+ const schema = strapi2.getModel(params.query.contentType);
357
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(schema);
358
+ const defaultLocale = await serviceUtils.getDefaultLocale();
359
+ let locale = null;
360
+ if (isLocalizedContentType) {
361
+ locale = params.query.locale || defaultLocale;
362
+ }
338
363
  const [{ results, pagination }, localeDictionary] = await Promise.all([
339
364
  query.findPage({
340
365
  ...params.query,
@@ -350,78 +375,76 @@ const createHistoryService = ({ strapi: strapi2 }) => {
350
375
  }),
351
376
  serviceUtils.getLocaleDictionary()
352
377
  ]);
353
- const populateEntryRelations = async (entry) => {
354
- const entryWithRelations = await Object.entries(entry.schema).reduce(
355
- async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
356
- const attributeValue = entry.data[attributeKey];
357
- const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
358
- if (attributeSchema.type === "media") {
359
- const permissionChecker2 = getService$1("permission-checker").create({
360
- userAbility: params.state.userAbility,
361
- model: "plugin::upload.file"
362
- });
363
- const response = await serviceUtils.buildMediaResponse(attributeValues);
364
- const sanitizedResults = await Promise.all(
365
- response.results.map((media) => permissionChecker2.sanitizeOutput(media))
366
- );
367
- return {
368
- ...await currentDataWithRelations,
369
- [attributeKey]: {
370
- results: sanitizedResults,
371
- meta: response.meta
372
- }
373
- };
378
+ const populateEntry = async (entry) => {
379
+ return strapiUtils.traverseEntity(
380
+ async (options, utils) => {
381
+ if (!options.attribute) return;
382
+ if (!options.value) return;
383
+ const currentValue = Array.isArray(options.value) ? options.value : [options.value];
384
+ if (options.attribute.type === "component") {
385
+ utils.remove("id");
374
386
  }
375
- if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
376
- if (attributeSchema.target === "admin::user") {
387
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
388
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
389
+ if (options.attribute.target === "admin::user") {
377
390
  const adminUsers = await Promise.all(
378
- attributeValues.map((userToPopulate) => {
391
+ currentValue.map((userToPopulate) => {
379
392
  if (userToPopulate == null) {
380
393
  return null;
381
394
  }
382
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
395
+ return strapi2.query("admin::user").findOne({
396
+ where: {
397
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
398
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
399
+ }
400
+ });
383
401
  })
384
402
  );
385
- return {
386
- ...await currentDataWithRelations,
387
- /**
388
- * Ideally we would return the same "{results: [], meta: {}}" shape, however,
389
- * when sanitizing the data as a whole in the controller before sending to the client,
390
- * the data for admin relation user is completely sanitized if we return an object here as opposed to an array.
391
- */
392
- [attributeKey]: adminUsers
393
- };
403
+ utils.set(options.key, adminUsers);
394
404
  }
395
- const permissionChecker2 = getService$1("permission-checker").create({
405
+ const permissionChecker2 = getService$2("permission-checker").create({
396
406
  userAbility: params.state.userAbility,
397
- model: attributeSchema.target
407
+ model: options.attribute.target
398
408
  });
399
409
  const response = await serviceUtils.buildRelationReponse(
400
- attributeValues,
401
- attributeSchema
410
+ currentValue,
411
+ options.attribute
402
412
  );
403
413
  const sanitizedResults = await Promise.all(
404
414
  response.results.map((media) => permissionChecker2.sanitizeOutput(media))
405
415
  );
406
- return {
407
- ...await currentDataWithRelations,
408
- [attributeKey]: {
409
- results: sanitizedResults,
410
- meta: response.meta
411
- }
412
- };
416
+ utils.set(options.key, {
417
+ results: sanitizedResults,
418
+ meta: response.meta
419
+ });
413
420
  }
414
- return currentDataWithRelations;
421
+ if (options.attribute.type === "media") {
422
+ const permissionChecker2 = getService$2("permission-checker").create({
423
+ userAbility: params.state.userAbility,
424
+ model: "plugin::upload.file"
425
+ });
426
+ const response = await serviceUtils.buildMediaResponse(currentValue);
427
+ const sanitizedResults = await Promise.all(
428
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
429
+ );
430
+ utils.set(options.key, {
431
+ results: sanitizedResults,
432
+ meta: response.meta
433
+ });
434
+ }
435
+ },
436
+ {
437
+ schema,
438
+ getModel: strapi2.getModel.bind(strapi2)
415
439
  },
416
- Promise.resolve(entry.data)
440
+ entry.data
417
441
  );
418
- return entryWithRelations;
419
442
  };
420
443
  const formattedResults = await Promise.all(
421
444
  results.map(async (result) => {
422
445
  return {
423
446
  ...result,
424
- data: await populateEntryRelations(result),
447
+ data: await populateEntry(result),
425
448
  meta: {
426
449
  unknownAttributes: serviceUtils.getSchemaAttributesDiff(
427
450
  result.schema,
@@ -452,30 +475,44 @@ const createHistoryService = ({ strapi: strapi2 }) => {
452
475
  // Clone to avoid mutating the original version data
453
476
  structuredClone(version.data)
454
477
  );
455
- const sanitizedSchemaAttributes = fp.omit(
456
- FIELDS_TO_IGNORE,
457
- contentTypeSchemaAttributes
458
- );
459
- const reducer = strapiUtils.async.reduce(Object.entries(sanitizedSchemaAttributes));
460
- const dataWithoutMissingRelations = await reducer(
461
- async (previousRelationAttributes, [name, attribute]) => {
462
- const versionRelationData = version.data[name];
463
- if (!versionRelationData) {
464
- return previousRelationAttributes;
478
+ const schema = structuredClone(version.schema);
479
+ schema.attributes = fp.omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
480
+ const dataWithoutMissingRelations = await strapiUtils.traverseEntity(
481
+ async (options, utils) => {
482
+ if (!options.attribute) return;
483
+ if (options.attribute.type === "component") {
484
+ utils.remove("id");
485
+ if (options.attribute.repeatable && options.value === null) {
486
+ utils.set(options.key, []);
487
+ }
465
488
  }
466
- if (attribute.type === "relation" && // TODO: handle polymorphic relations
467
- attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
468
- const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
469
- previousRelationAttributes[name] = data2;
489
+ if (options.attribute.type === "dynamiczone") {
490
+ if (options.value === null) {
491
+ utils.set(options.key, []);
492
+ }
470
493
  }
471
- if (attribute.type === "media") {
472
- const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
473
- previousRelationAttributes[name] = data2;
494
+ if (options.attribute.type === "relation" && // TODO: handle polymorphic relations
495
+ options.attribute.relation !== "morphToOne" && options.attribute.relation !== "morphToMany") {
496
+ if (!options.value) return;
497
+ const data2 = await serviceUtils.getRelationRestoreValue(
498
+ options.value,
499
+ options.attribute
500
+ );
501
+ utils.set(options.key, data2);
502
+ }
503
+ if (options.attribute.type === "media") {
504
+ if (!options.value) return;
505
+ const data2 = await serviceUtils.getMediaRestoreValue(
506
+ options.value
507
+ );
508
+ utils.set(options.key, data2);
474
509
  }
475
- return previousRelationAttributes;
476
510
  },
477
- // Clone to avoid mutating the original version data
478
- structuredClone(dataWithoutAddedAttributes)
511
+ {
512
+ schema,
513
+ getModel: strapi2.getModel.bind(strapi2)
514
+ },
515
+ dataWithoutAddedAttributes
479
516
  );
480
517
  const data = fp.omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
481
518
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -490,13 +527,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
490
527
  }
491
528
  };
492
529
  };
530
+ const shouldCreateHistoryVersion = (context) => {
531
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
532
+ return false;
533
+ }
534
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
535
+ return false;
536
+ }
537
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
538
+ return false;
539
+ }
540
+ if (!context.contentType.uid.startsWith("api::")) {
541
+ return false;
542
+ }
543
+ return true;
544
+ };
545
+ const getSchemas = (uid2) => {
546
+ const attributesSchema = strapi.getModel(uid2).attributes;
547
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
548
+ (currentComponentSchemas, key) => {
549
+ const fieldSchema = attributesSchema[key];
550
+ if (fieldSchema.type === "component") {
551
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
552
+ return {
553
+ ...currentComponentSchemas,
554
+ [fieldSchema.component]: componentSchema
555
+ };
556
+ }
557
+ return currentComponentSchemas;
558
+ },
559
+ {}
560
+ );
561
+ return {
562
+ schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
563
+ componentsSchemas
564
+ };
565
+ };
493
566
  const createLifecyclesService = ({ strapi: strapi2 }) => {
494
567
  const state = {
495
568
  deleteExpiredJob: null,
496
569
  isInitialized: false
497
570
  };
498
- const query = strapi2.db.query(HISTORY_VERSION_UID);
499
- const historyService = getService(strapi2, "history");
500
571
  const serviceUtils = createServiceUtils({ strapi: strapi2 });
501
572
  return {
502
573
  async bootstrap() {
@@ -504,73 +575,62 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
504
575
  return;
505
576
  }
506
577
  strapi2.documents.use(async (context, next) => {
507
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
508
- return next();
509
- }
510
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
511
- return next();
512
- }
513
- const contentTypeUid = context.contentType.uid;
514
- if (!contentTypeUid.startsWith("api::")) {
515
- return next();
516
- }
517
578
  const result = await next();
518
- const documentContext = {
519
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
520
- locale: context.params?.locale
521
- };
579
+ if (!shouldCreateHistoryVersion(context)) {
580
+ return result;
581
+ }
582
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
522
583
  const defaultLocale = await serviceUtils.getDefaultLocale();
523
- const locale = documentContext.locale || defaultLocale;
524
- if (Array.isArray(locale)) {
525
- strapi2.log.warn(
526
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
527
- );
528
- return next();
584
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
585
+ if (!locales.length) {
586
+ return result;
529
587
  }
530
- const document = await strapi2.documents(contentTypeUid).findOne({
531
- documentId: documentContext.documentId,
532
- locale,
533
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
588
+ const uid2 = context.contentType.uid;
589
+ const schemas = getSchemas(uid2);
590
+ const model = strapi2.getModel(uid2);
591
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
592
+ const localeEntries = await strapi2.db.query(uid2).findMany({
593
+ where: {
594
+ documentId,
595
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
596
+ ...strapiUtils.contentTypes.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
597
+ },
598
+ populate: serviceUtils.getDeepPopulate(
599
+ uid2,
600
+ true
601
+ /* use database syntax */
602
+ )
534
603
  });
535
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
536
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
537
- const componentsSchemas = Object.keys(
538
- attributesSchema
539
- ).reduce((currentComponentSchemas, key) => {
540
- const fieldSchema = attributesSchema[key];
541
- if (fieldSchema.type === "component") {
542
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
543
- return {
544
- ...currentComponentSchemas,
545
- [fieldSchema.component]: componentSchema
546
- };
547
- }
548
- return currentComponentSchemas;
549
- }, {});
550
604
  await strapi2.db.transaction(async ({ onCommit }) => {
551
- onCommit(() => {
552
- historyService.createVersion({
553
- contentType: contentTypeUid,
554
- data: fp.omit(FIELDS_TO_IGNORE, document),
555
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
556
- componentsSchemas,
557
- relatedDocumentId: documentContext.documentId,
558
- locale,
559
- status
560
- });
605
+ onCommit(async () => {
606
+ for (const entry of localeEntries) {
607
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
608
+ await getService$1(strapi2, "history").createVersion({
609
+ contentType: uid2,
610
+ data: fp.omit(FIELDS_TO_IGNORE, entry),
611
+ relatedDocumentId: documentId,
612
+ locale: entry.locale,
613
+ status,
614
+ ...schemas
615
+ });
616
+ }
561
617
  });
562
618
  });
563
619
  return result;
564
620
  });
565
- state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
621
+ state.deleteExpiredJob = nodeSchedule.scheduleJob("historyDaily", "0 0 * * *", () => {
566
622
  const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
567
623
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
568
- query.deleteMany({
624
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
569
625
  where: {
570
626
  created_at: {
571
- $lt: expirationDate.toISOString()
627
+ $lt: expirationDate
572
628
  }
573
629
  }
630
+ }).catch((error) => {
631
+ if (error instanceof Error) {
632
+ strapi2.log.error("Error deleting expired history versions", error.message);
633
+ }
574
634
  });
575
635
  });
576
636
  state.isInitialized = true;
@@ -582,17 +642,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
582
642
  }
583
643
  };
584
644
  };
585
- const services$1 = {
645
+ const services$2 = {
586
646
  history: createHistoryService,
587
647
  lifecycles: createLifecyclesService
588
648
  };
589
- const info = { pluginName: "content-manager", type: "admin" };
649
+ const info$1 = { pluginName: "content-manager", type: "admin" };
590
650
  const historyVersionRouter = {
591
651
  type: "admin",
592
652
  routes: [
593
653
  {
594
654
  method: "GET",
595
- info,
655
+ info: info$1,
596
656
  path: "/history-versions",
597
657
  handler: "history-version.findMany",
598
658
  config: {
@@ -601,7 +661,7 @@ const historyVersionRouter = {
601
661
  },
602
662
  {
603
663
  method: "PUT",
604
- info,
664
+ info: info$1,
605
665
  path: "/history-versions/:versionId/restore",
606
666
  handler: "history-version.restoreVersion",
607
667
  config: {
@@ -610,7 +670,7 @@ const historyVersionRouter = {
610
670
  }
611
671
  ]
612
672
  };
613
- const routes$1 = {
673
+ const routes$2 = {
614
674
  "history-version": historyVersionRouter
615
675
  };
616
676
  const historyVersion = {
@@ -657,21 +717,21 @@ const historyVersion = {
657
717
  }
658
718
  }
659
719
  };
660
- const getFeature = () => {
720
+ const getFeature$1 = () => {
661
721
  if (strapi.ee.features.isEnabled("cms-content-history")) {
662
722
  return {
663
723
  register({ strapi: strapi2 }) {
664
724
  strapi2.get("models").add(historyVersion);
665
725
  },
666
726
  bootstrap({ strapi: strapi2 }) {
667
- getService(strapi2, "lifecycles").bootstrap();
727
+ getService$1(strapi2, "lifecycles").bootstrap();
668
728
  },
669
729
  destroy({ strapi: strapi2 }) {
670
- getService(strapi2, "lifecycles").destroy();
730
+ getService$1(strapi2, "lifecycles").destroy();
671
731
  },
672
- controllers: controllers$1,
673
- services: services$1,
674
- routes: routes$1
732
+ controllers: controllers$2,
733
+ services: services$2,
734
+ routes: routes$2
675
735
  };
676
736
  }
677
737
  return {
@@ -680,9 +740,201 @@ const getFeature = () => {
680
740
  }
681
741
  };
682
742
  };
683
- const history = getFeature();
743
+ const history = getFeature$1();
744
+ const info = { pluginName: "content-manager", type: "admin" };
745
+ const previewRouter = {
746
+ type: "admin",
747
+ routes: [
748
+ {
749
+ method: "GET",
750
+ info,
751
+ path: "/preview/url/:contentType",
752
+ handler: "preview.getPreviewUrl",
753
+ config: {
754
+ policies: ["admin::isAuthenticatedAdmin"]
755
+ }
756
+ }
757
+ ]
758
+ };
759
+ const routes$1 = {
760
+ preview: previewRouter
761
+ };
762
+ function getService(strapi2, name) {
763
+ return strapi2.service(`plugin::content-manager.${name}`);
764
+ }
765
+ const getPreviewUrlSchema = yup__namespace.object().shape({
766
+ // Will be undefined for single types
767
+ documentId: yup__namespace.string(),
768
+ locale: yup__namespace.string().nullable(),
769
+ status: yup__namespace.string()
770
+ }).required();
771
+ const validatePreviewUrl = async (strapi2, uid2, params) => {
772
+ await strapiUtils.validateYupSchema(getPreviewUrlSchema)(params);
773
+ const newParams = fp.pick(["documentId", "locale", "status"], params);
774
+ const model = strapi2.getModel(uid2);
775
+ if (!model || model.modelType !== "contentType") {
776
+ throw new strapiUtils.errors.ValidationError("Invalid content type");
777
+ }
778
+ const isSingleType = model?.kind === "singleType";
779
+ if (!isSingleType && !params.documentId) {
780
+ throw new strapiUtils.errors.ValidationError("documentId is required for Collection Types");
781
+ }
782
+ if (isSingleType) {
783
+ const doc = await strapi2.documents(uid2).findFirst();
784
+ if (!doc) {
785
+ throw new strapiUtils.errors.NotFoundError("Document not found");
786
+ }
787
+ newParams.documentId = doc?.documentId;
788
+ }
789
+ if (!newParams.status) {
790
+ const isDPEnabled = model?.options?.draftAndPublish;
791
+ newParams.status = isDPEnabled ? "draft" : "published";
792
+ }
793
+ return newParams;
794
+ };
795
+ const createPreviewController = () => {
796
+ return {
797
+ /**
798
+ * Transforms an entry into a preview URL, so that it can be previewed
799
+ * in the Content Manager.
800
+ */
801
+ async getPreviewUrl(ctx) {
802
+ const uid2 = ctx.params.contentType;
803
+ const query = ctx.request.query;
804
+ const params = await validatePreviewUrl(strapi, uid2, query);
805
+ const previewService = getService(strapi, "preview");
806
+ const url = await previewService.getPreviewUrl(uid2, params);
807
+ if (!url) {
808
+ ctx.status = 204;
809
+ }
810
+ return {
811
+ data: { url }
812
+ };
813
+ }
814
+ };
815
+ };
816
+ const controllers$1 = {
817
+ preview: createPreviewController
818
+ /**
819
+ * Casting is needed because the types aren't aware that Strapi supports
820
+ * passing a controller factory as the value, instead of a controller object directly
821
+ */
822
+ };
823
+ const createPreviewService = ({ strapi: strapi2 }) => {
824
+ const config = getService(strapi2, "preview-config");
825
+ return {
826
+ async getPreviewUrl(uid2, params) {
827
+ const handler = config.getPreviewHandler();
828
+ try {
829
+ return handler(uid2, params);
830
+ } catch (error) {
831
+ strapi2.log.error(`Failed to get preview URL: ${error}`);
832
+ throw new strapiUtils.errors.ApplicationError("Failed to get preview URL");
833
+ }
834
+ return;
835
+ }
836
+ };
837
+ };
838
+ const extendMiddlewareConfiguration = (middleware = { name: "", config: {} }) => {
839
+ const middlewares = strapi.config.get("middlewares");
840
+ const configuredMiddlewares = middlewares.map((currentMiddleware) => {
841
+ if (currentMiddleware === middleware.name) {
842
+ return middleware;
843
+ }
844
+ if (currentMiddleware.name === middleware.name) {
845
+ return fp.mergeWith(
846
+ (objValue, srcValue) => {
847
+ if (Array.isArray(objValue)) {
848
+ return objValue.concat(srcValue);
849
+ }
850
+ return void 0;
851
+ },
852
+ currentMiddleware,
853
+ middleware
854
+ );
855
+ }
856
+ return currentMiddleware;
857
+ });
858
+ strapi.config.set("middlewares", configuredMiddlewares);
859
+ };
860
+ const createPreviewConfigService = ({ strapi: strapi2 }) => {
861
+ return {
862
+ register() {
863
+ if (!this.isEnabled()) {
864
+ return;
865
+ }
866
+ const config = strapi2.config.get("admin.preview");
867
+ if (config.config?.allowedOrigins) {
868
+ extendMiddlewareConfiguration({
869
+ name: "strapi::security",
870
+ config: {
871
+ contentSecurityPolicy: {
872
+ directives: {
873
+ "frame-src": config.config.allowedOrigins
874
+ }
875
+ }
876
+ }
877
+ });
878
+ }
879
+ },
880
+ isEnabled() {
881
+ const config = strapi2.config.get("admin.preview");
882
+ if (!config) {
883
+ return false;
884
+ }
885
+ return config?.enabled ?? true;
886
+ },
887
+ /**
888
+ * Validate if the configuration is valid
889
+ */
890
+ validate() {
891
+ if (!this.isEnabled()) {
892
+ return;
893
+ }
894
+ const handler = this.getPreviewHandler();
895
+ if (typeof handler !== "function") {
896
+ throw new strapiUtils.errors.ValidationError(
897
+ "Preview configuration is invalid. Handler must be a function"
898
+ );
899
+ }
900
+ },
901
+ /**
902
+ * Utility to get the preview handler from the configuration
903
+ */
904
+ getPreviewHandler() {
905
+ const config = strapi2.config.get("admin.preview");
906
+ const emptyHandler = () => {
907
+ return void 0;
908
+ };
909
+ if (!this.isEnabled()) {
910
+ return emptyHandler;
911
+ }
912
+ return config?.config?.handler || emptyHandler;
913
+ }
914
+ };
915
+ };
916
+ const services$1 = {
917
+ preview: createPreviewService,
918
+ "preview-config": createPreviewConfigService
919
+ };
920
+ const getFeature = () => {
921
+ return {
922
+ register() {
923
+ const config = getService(strapi, "preview-config");
924
+ config.validate();
925
+ config.register();
926
+ },
927
+ bootstrap() {
928
+ },
929
+ routes: routes$1,
930
+ controllers: controllers$1,
931
+ services: services$1
932
+ };
933
+ };
934
+ const preview = getFeature();
684
935
  const register = async ({ strapi: strapi2 }) => {
685
936
  await history.register?.({ strapi: strapi2 });
937
+ await preview.register?.({ strapi: strapi2 });
686
938
  };
687
939
  const ALLOWED_WEBHOOK_EVENTS = {
688
940
  ENTRY_PUBLISH: "entry.publish",
@@ -692,11 +944,12 @@ const bootstrap = async () => {
692
944
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
693
945
  strapi.get("webhookStore").addAllowedEvent(key, value);
694
946
  });
695
- getService$1("field-sizes").setCustomFieldInputSizes();
696
- await getService$1("components").syncConfigurations();
697
- await getService$1("content-types").syncConfigurations();
698
- await getService$1("permission").registerPermissions();
947
+ getService$2("field-sizes").setCustomFieldInputSizes();
948
+ await getService$2("components").syncConfigurations();
949
+ await getService$2("content-types").syncConfigurations();
950
+ await getService$2("permission").registerPermissions();
699
951
  await history.bootstrap?.({ strapi });
952
+ await preview.bootstrap?.({ strapi });
700
953
  };
701
954
  const destroy = async ({ strapi: strapi2 }) => {
702
955
  await history.destroy?.({ strapi: strapi2 });
@@ -1186,7 +1439,8 @@ const admin = {
1186
1439
  };
1187
1440
  const routes = {
1188
1441
  admin,
1189
- ...history.routes ? history.routes : {}
1442
+ ...history.routes ? history.routes : {},
1443
+ ...preview.routes ? preview.routes : {}
1190
1444
  };
1191
1445
  const hasPermissionsSchema = strapiUtils.yup.object({
1192
1446
  actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
@@ -1197,6 +1451,11 @@ const { createPolicy } = strapiUtils.policy;
1197
1451
  const hasPermissions = createPolicy({
1198
1452
  name: "plugin::content-manager.hasPermissions",
1199
1453
  validator: validateHasPermissionsInput,
1454
+ /**
1455
+ * NOTE: Action aliases are currently not checked at this level (policy).
1456
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1457
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1458
+ */
1200
1459
  handler(ctx, config = {}) {
1201
1460
  const { actions = [], hasAtLeastOne = false } = config;
1202
1461
  const { userAbility } = ctx.state;
@@ -1244,8 +1503,7 @@ const isSortable = (schema, name) => {
1244
1503
  if (!___default.default.has(schema.attributes, name)) {
1245
1504
  return false;
1246
1505
  }
1247
- if (schema.modelType === "component" && name === "id")
1248
- return false;
1506
+ if (schema.modelType === "component" && name === "id") return false;
1249
1507
  const attribute = schema.attributes[name];
1250
1508
  if (NON_SORTABLES.includes(attribute.type)) {
1251
1509
  return false;
@@ -1390,8 +1648,7 @@ const createDefaultSettings = async (schema) => {
1390
1648
  };
1391
1649
  };
1392
1650
  const syncSettings = async (configuration, schema) => {
1393
- if (fp.isEmpty(configuration.settings))
1394
- return createDefaultSettings(schema);
1651
+ if (fp.isEmpty(configuration.settings)) return createDefaultSettings(schema);
1395
1652
  const defaultField = getDefaultMainField(schema);
1396
1653
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1397
1654
  return {
@@ -1438,7 +1695,7 @@ const createMetadasSchema = (schema) => {
1438
1695
  if (!value) {
1439
1696
  return strapiUtils.yup.string();
1440
1697
  }
1441
- const targetSchema = getService$1("content-types").findContentType(
1698
+ const targetSchema = getService$2("content-types").findContentType(
1442
1699
  schema.attributes[key].targetModel
1443
1700
  );
1444
1701
  if (!targetSchema) {
@@ -1567,8 +1824,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1567
1824
  }
1568
1825
  switch (attribute.type) {
1569
1826
  case "relation": {
1570
- if (canCreate(attributePath))
1571
- return body2;
1827
+ if (canCreate(attributePath)) return body2;
1572
1828
  return fp.set(attributePath, { set: [] }, body2);
1573
1829
  }
1574
1830
  case "component": {
@@ -1578,8 +1834,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1578
1834
  ]);
1579
1835
  }
1580
1836
  default: {
1581
- if (canCreate(attributePath))
1582
- return body2;
1837
+ if (canCreate(attributePath)) return body2;
1583
1838
  return fp.set(attributePath, null, body2);
1584
1839
  }
1585
1840
  }
@@ -1590,9 +1845,11 @@ const multipleLocaleSchema = strapiUtils.yup.lazy(
1590
1845
  (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1591
1846
  );
1592
1847
  const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1593
- const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1848
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1594
1849
  const { allowMultipleLocales } = opts;
1595
- const { locale, status, ...rest } = request || {};
1850
+ const { locale, status: providedStatus, ...rest } = request || {};
1851
+ const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1852
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1596
1853
  const schema = strapiUtils.yup.object().shape({
1597
1854
  locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1598
1855
  status: statusSchema
@@ -1605,7 +1862,7 @@ const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales
1605
1862
  }
1606
1863
  };
1607
1864
  const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1608
- const documentMetadata2 = getService$1("document-metadata");
1865
+ const documentMetadata2 = getService$2("document-metadata");
1609
1866
  const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1610
1867
  let {
1611
1868
  meta: { availableLocales, availableStatus }
@@ -1631,8 +1888,8 @@ const createDocument = async (ctx, opts) => {
1631
1888
  const { userAbility, user } = ctx.state;
1632
1889
  const { model } = ctx.params;
1633
1890
  const { body } = ctx.request;
1634
- const documentManager2 = getService$1("document-manager");
1635
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1891
+ const documentManager2 = getService$2("document-manager");
1892
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1636
1893
  if (permissionChecker2.cannot.create()) {
1637
1894
  throw new strapiUtils.errors.ForbiddenError();
1638
1895
  }
@@ -1640,7 +1897,7 @@ const createDocument = async (ctx, opts) => {
1640
1897
  const setCreator = strapiUtils.setCreatorFields({ user });
1641
1898
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1642
1899
  const sanitizedBody = await sanitizeFn(body);
1643
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1900
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1644
1901
  return documentManager2.create(model, {
1645
1902
  data: sanitizedBody,
1646
1903
  locale,
@@ -1652,14 +1909,14 @@ const updateDocument = async (ctx, opts) => {
1652
1909
  const { userAbility, user } = ctx.state;
1653
1910
  const { id, model } = ctx.params;
1654
1911
  const { body } = ctx.request;
1655
- const documentManager2 = getService$1("document-manager");
1656
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1912
+ const documentManager2 = getService$2("document-manager");
1913
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1657
1914
  if (permissionChecker2.cannot.update()) {
1658
1915
  throw new strapiUtils.errors.ForbiddenError();
1659
1916
  }
1660
1917
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1661
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1662
- const { locale } = await getDocumentLocaleAndStatus(body);
1918
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1919
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1663
1920
  const [documentVersion, documentExists] = await Promise.all([
1664
1921
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1665
1922
  documentManager2.exists(model, id)
@@ -1675,7 +1932,7 @@ const updateDocument = async (ctx, opts) => {
1675
1932
  throw new strapiUtils.errors.ForbiddenError();
1676
1933
  }
1677
1934
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1678
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1935
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1679
1936
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1680
1937
  const sanitizedBody = await sanitizeFn(body);
1681
1938
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1689,15 +1946,15 @@ const collectionTypes = {
1689
1946
  const { userAbility } = ctx.state;
1690
1947
  const { model } = ctx.params;
1691
1948
  const { query } = ctx.request;
1692
- const documentMetadata2 = getService$1("document-metadata");
1693
- const documentManager2 = getService$1("document-manager");
1694
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1949
+ const documentMetadata2 = getService$2("document-metadata");
1950
+ const documentManager2 = getService$2("document-manager");
1951
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1695
1952
  if (permissionChecker2.cannot.read()) {
1696
1953
  return ctx.forbidden();
1697
1954
  }
1698
1955
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1699
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1700
- const { locale, status } = await getDocumentLocaleAndStatus(query);
1956
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1957
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1701
1958
  const { results: documents, pagination } = await documentManager2.findPage(
1702
1959
  { ...permissionQuery, populate, locale, status },
1703
1960
  model
@@ -1725,14 +1982,14 @@ const collectionTypes = {
1725
1982
  async findOne(ctx) {
1726
1983
  const { userAbility } = ctx.state;
1727
1984
  const { model, id } = ctx.params;
1728
- const documentManager2 = getService$1("document-manager");
1729
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
1985
+ const documentManager2 = getService$2("document-manager");
1986
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1730
1987
  if (permissionChecker2.cannot.read()) {
1731
1988
  return ctx.forbidden();
1732
1989
  }
1733
1990
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1734
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1735
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1991
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1992
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1736
1993
  const version = await documentManager2.findOne(id, model, {
1737
1994
  populate,
1738
1995
  locale,
@@ -1747,7 +2004,7 @@ const collectionTypes = {
1747
2004
  permissionChecker2,
1748
2005
  model,
1749
2006
  // @ts-expect-error TODO: fix
1750
- { id, locale, publishedAt: null },
2007
+ { documentId: id, locale, publishedAt: null },
1751
2008
  { availableLocales: true, availableStatus: false }
1752
2009
  );
1753
2010
  ctx.body = { data: {}, meta };
@@ -1762,7 +2019,7 @@ const collectionTypes = {
1762
2019
  async create(ctx) {
1763
2020
  const { userAbility } = ctx.state;
1764
2021
  const { model } = ctx.params;
1765
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2022
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1766
2023
  const [totalEntries, document] = await Promise.all([
1767
2024
  strapi.db.query(model).count(),
1768
2025
  createDocument(ctx)
@@ -1783,7 +2040,7 @@ const collectionTypes = {
1783
2040
  async update(ctx) {
1784
2041
  const { userAbility } = ctx.state;
1785
2042
  const { model } = ctx.params;
1786
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2043
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1787
2044
  const updatedVersion = await updateDocument(ctx);
1788
2045
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1789
2046
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
@@ -1792,14 +2049,14 @@ const collectionTypes = {
1792
2049
  const { userAbility, user } = ctx.state;
1793
2050
  const { model, sourceId: id } = ctx.params;
1794
2051
  const { body } = ctx.request;
1795
- const documentManager2 = getService$1("document-manager");
1796
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2052
+ const documentManager2 = getService$2("document-manager");
2053
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1797
2054
  if (permissionChecker2.cannot.create()) {
1798
2055
  return ctx.forbidden();
1799
2056
  }
1800
2057
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1801
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1802
- const { locale } = await getDocumentLocaleAndStatus(body);
2058
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2059
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1803
2060
  const document = await documentManager2.findOne(id, model, {
1804
2061
  populate,
1805
2062
  locale,
@@ -1837,14 +2094,14 @@ const collectionTypes = {
1837
2094
  async delete(ctx) {
1838
2095
  const { userAbility } = ctx.state;
1839
2096
  const { id, model } = ctx.params;
1840
- const documentManager2 = getService$1("document-manager");
1841
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2097
+ const documentManager2 = getService$2("document-manager");
2098
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1842
2099
  if (permissionChecker2.cannot.delete()) {
1843
2100
  return ctx.forbidden();
1844
2101
  }
1845
2102
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1846
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1847
- const { locale } = await getDocumentLocaleAndStatus(ctx.query);
2103
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2104
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1848
2105
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1849
2106
  if (documentLocales.length === 0) {
1850
2107
  return ctx.notFound();
@@ -1865,19 +2122,42 @@ const collectionTypes = {
1865
2122
  const { userAbility } = ctx.state;
1866
2123
  const { id, model } = ctx.params;
1867
2124
  const { body } = ctx.request;
1868
- const documentManager2 = getService$1("document-manager");
1869
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2125
+ const documentManager2 = getService$2("document-manager");
2126
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1870
2127
  if (permissionChecker2.cannot.publish()) {
1871
2128
  return ctx.forbidden();
1872
2129
  }
1873
2130
  const publishedDocument = await strapi.db.transaction(async () => {
1874
2131
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1875
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1876
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
2132
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2133
+ let document;
2134
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2135
+ const isCreate = fp.isNil(id);
2136
+ if (isCreate) {
2137
+ if (permissionChecker2.cannot.create()) {
2138
+ throw new strapiUtils.errors.ForbiddenError();
2139
+ }
2140
+ document = await createDocument(ctx, { populate });
2141
+ }
2142
+ const isUpdate = !isCreate;
2143
+ if (isUpdate) {
2144
+ const documentExists = documentManager2.exists(model, id);
2145
+ if (!documentExists) {
2146
+ throw new strapiUtils.errors.NotFoundError("Document not found");
2147
+ }
2148
+ document = await documentManager2.findOne(id, model, { populate, locale });
2149
+ if (!document) {
2150
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
2151
+ throw new strapiUtils.errors.ForbiddenError();
2152
+ }
2153
+ document = await updateDocument(ctx);
2154
+ } else if (permissionChecker2.can.update(document)) {
2155
+ await updateDocument(ctx);
2156
+ }
2157
+ }
1877
2158
  if (permissionChecker2.cannot.publish(document)) {
1878
2159
  throw new strapiUtils.errors.ForbiddenError();
1879
2160
  }
1880
- const { locale } = await getDocumentLocaleAndStatus(body);
1881
2161
  const publishResult = await documentManager2.publish(document.documentId, model, {
1882
2162
  locale
1883
2163
  // TODO: Allow setting creator fields on publish
@@ -1897,14 +2177,16 @@ const collectionTypes = {
1897
2177
  const { body } = ctx.request;
1898
2178
  const { documentIds } = body;
1899
2179
  await validateBulkActionInput(body);
1900
- const documentManager2 = getService$1("document-manager");
1901
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2180
+ const documentManager2 = getService$2("document-manager");
2181
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1902
2182
  if (permissionChecker2.cannot.publish()) {
1903
2183
  return ctx.forbidden();
1904
2184
  }
1905
2185
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1906
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1907
- const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
2186
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
2187
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2188
+ allowMultipleLocales: true
2189
+ });
1908
2190
  const entityPromises = documentIds.map(
1909
2191
  (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1910
2192
  );
@@ -1926,12 +2208,14 @@ const collectionTypes = {
1926
2208
  const { body } = ctx.request;
1927
2209
  const { documentIds } = body;
1928
2210
  await validateBulkActionInput(body);
1929
- const documentManager2 = getService$1("document-manager");
1930
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2211
+ const documentManager2 = getService$2("document-manager");
2212
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1931
2213
  if (permissionChecker2.cannot.unpublish()) {
1932
2214
  return ctx.forbidden();
1933
2215
  }
1934
- const { locale } = await getDocumentLocaleAndStatus(body);
2216
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2217
+ allowMultipleLocales: true
2218
+ });
1935
2219
  const entityPromises = documentIds.map(
1936
2220
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1937
2221
  );
@@ -1954,8 +2238,8 @@ const collectionTypes = {
1954
2238
  const {
1955
2239
  body: { discardDraft, ...body }
1956
2240
  } = ctx.request;
1957
- const documentManager2 = getService$1("document-manager");
1958
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2241
+ const documentManager2 = getService$2("document-manager");
2242
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1959
2243
  if (permissionChecker2.cannot.unpublish()) {
1960
2244
  return ctx.forbidden();
1961
2245
  }
@@ -1963,8 +2247,8 @@ const collectionTypes = {
1963
2247
  return ctx.forbidden();
1964
2248
  }
1965
2249
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1966
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1967
- const { locale } = await getDocumentLocaleAndStatus(body);
2250
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2251
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1968
2252
  const document = await documentManager2.findOne(id, model, {
1969
2253
  populate,
1970
2254
  locale,
@@ -1994,14 +2278,14 @@ const collectionTypes = {
1994
2278
  const { userAbility } = ctx.state;
1995
2279
  const { id, model } = ctx.params;
1996
2280
  const { body } = ctx.request;
1997
- const documentManager2 = getService$1("document-manager");
1998
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2281
+ const documentManager2 = getService$2("document-manager");
2282
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1999
2283
  if (permissionChecker2.cannot.discard()) {
2000
2284
  return ctx.forbidden();
2001
2285
  }
2002
2286
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2003
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2004
- const { locale } = await getDocumentLocaleAndStatus(body);
2287
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2288
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2005
2289
  const document = await documentManager2.findOne(id, model, {
2006
2290
  populate,
2007
2291
  locale,
@@ -2025,14 +2309,14 @@ const collectionTypes = {
2025
2309
  const { query, body } = ctx.request;
2026
2310
  const { documentIds } = body;
2027
2311
  await validateBulkActionInput(body);
2028
- const documentManager2 = getService$1("document-manager");
2029
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2312
+ const documentManager2 = getService$2("document-manager");
2313
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2030
2314
  if (permissionChecker2.cannot.delete()) {
2031
2315
  return ctx.forbidden();
2032
2316
  }
2033
2317
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2034
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2035
- const { locale } = await getDocumentLocaleAndStatus(body);
2318
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2319
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2036
2320
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2037
2321
  populate,
2038
2322
  locale
@@ -2052,14 +2336,14 @@ const collectionTypes = {
2052
2336
  async countDraftRelations(ctx) {
2053
2337
  const { userAbility } = ctx.state;
2054
2338
  const { model, id } = ctx.params;
2055
- const documentManager2 = getService$1("document-manager");
2056
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2339
+ const documentManager2 = getService$2("document-manager");
2340
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2057
2341
  if (permissionChecker2.cannot.read()) {
2058
2342
  return ctx.forbidden();
2059
2343
  }
2060
2344
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2061
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2062
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
2345
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2346
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2063
2347
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2064
2348
  if (!entity) {
2065
2349
  return ctx.notFound();
@@ -2077,12 +2361,12 @@ const collectionTypes = {
2077
2361
  const ids = ctx.request.query.documentIds;
2078
2362
  const locale = ctx.request.query.locale;
2079
2363
  const { model } = ctx.params;
2080
- const documentManager2 = getService$1("document-manager");
2081
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2364
+ const documentManager2 = getService$2("document-manager");
2365
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2082
2366
  if (permissionChecker2.cannot.read()) {
2083
2367
  return ctx.forbidden();
2084
2368
  }
2085
- const entities = await documentManager2.findMany(
2369
+ const documents = await documentManager2.findMany(
2086
2370
  {
2087
2371
  filters: {
2088
2372
  documentId: ids
@@ -2091,7 +2375,7 @@ const collectionTypes = {
2091
2375
  },
2092
2376
  model
2093
2377
  );
2094
- if (!entities) {
2378
+ if (!documents) {
2095
2379
  return ctx.notFound();
2096
2380
  }
2097
2381
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2102,13 +2386,13 @@ const collectionTypes = {
2102
2386
  };
2103
2387
  const components$1 = {
2104
2388
  findComponents(ctx) {
2105
- const components2 = getService$1("components").findAllComponents();
2106
- const { toDto } = getService$1("data-mapper");
2389
+ const components2 = getService$2("components").findAllComponents();
2390
+ const { toDto } = getService$2("data-mapper");
2107
2391
  ctx.body = { data: components2.map(toDto) };
2108
2392
  },
2109
2393
  async findComponentConfiguration(ctx) {
2110
2394
  const { uid: uid2 } = ctx.params;
2111
- const componentService = getService$1("components");
2395
+ const componentService = getService$2("components");
2112
2396
  const component = componentService.findComponent(uid2);
2113
2397
  if (!component) {
2114
2398
  return ctx.notFound("component.notFound");
@@ -2125,7 +2409,7 @@ const components$1 = {
2125
2409
  async updateComponentConfiguration(ctx) {
2126
2410
  const { uid: uid2 } = ctx.params;
2127
2411
  const { body } = ctx.request;
2128
- const componentService = getService$1("components");
2412
+ const componentService = getService$2("components");
2129
2413
  const component = componentService.findComponent(uid2);
2130
2414
  if (!component) {
2131
2415
  return ctx.notFound("component.notFound");
@@ -2159,12 +2443,12 @@ const contentTypes = {
2159
2443
  } catch (error) {
2160
2444
  return ctx.send({ error }, 400);
2161
2445
  }
2162
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2163
- const { toDto } = getService$1("data-mapper");
2446
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2447
+ const { toDto } = getService$2("data-mapper");
2164
2448
  ctx.body = { data: contentTypes2.map(toDto) };
2165
2449
  },
2166
2450
  async findContentTypesSettings(ctx) {
2167
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2451
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2168
2452
  const contentTypes2 = await findAllContentTypes();
2169
2453
  const configurations = await Promise.all(
2170
2454
  contentTypes2.map(async (contentType) => {
@@ -2178,7 +2462,7 @@ const contentTypes = {
2178
2462
  },
2179
2463
  async findContentTypeConfiguration(ctx) {
2180
2464
  const { uid: uid2 } = ctx.params;
2181
- const contentTypeService = getService$1("content-types");
2465
+ const contentTypeService = getService$2("content-types");
2182
2466
  const contentType = await contentTypeService.findContentType(uid2);
2183
2467
  if (!contentType) {
2184
2468
  return ctx.notFound("contentType.notFound");
@@ -2200,13 +2484,13 @@ const contentTypes = {
2200
2484
  const { userAbility } = ctx.state;
2201
2485
  const { uid: uid2 } = ctx.params;
2202
2486
  const { body } = ctx.request;
2203
- const contentTypeService = getService$1("content-types");
2204
- const metricsService = getService$1("metrics");
2487
+ const contentTypeService = getService$2("content-types");
2488
+ const metricsService = getService$2("metrics");
2205
2489
  const contentType = await contentTypeService.findContentType(uid2);
2206
2490
  if (!contentType) {
2207
2491
  return ctx.notFound("contentType.notFound");
2208
2492
  }
2209
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2493
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2210
2494
  return ctx.forbidden();
2211
2495
  }
2212
2496
  let input;
@@ -2239,10 +2523,10 @@ const contentTypes = {
2239
2523
  };
2240
2524
  const init = {
2241
2525
  getInitData(ctx) {
2242
- const { toDto } = getService$1("data-mapper");
2243
- const { findAllComponents } = getService$1("components");
2244
- const { getAllFieldSizes } = getService$1("field-sizes");
2245
- const { findAllContentTypes } = getService$1("content-types");
2526
+ const { toDto } = getService$2("data-mapper");
2527
+ const { findAllComponents } = getService$2("components");
2528
+ const { getAllFieldSizes } = getService$2("field-sizes");
2529
+ const { findAllContentTypes } = getService$2("content-types");
2246
2530
  ctx.body = {
2247
2531
  data: {
2248
2532
  fieldSizes: getAllFieldSizes(),
@@ -2278,36 +2562,41 @@ const addFiltersClause = (params, filtersClause) => {
2278
2562
  params.filters.$and.push(filtersClause);
2279
2563
  };
2280
2564
  const sanitizeMainField = (model, mainField, userAbility) => {
2281
- const permissionChecker2 = getService$1("permission-checker").create({
2565
+ const permissionChecker2 = getService$2("permission-checker").create({
2282
2566
  userAbility,
2283
2567
  model: model.uid
2284
2568
  });
2285
- if (!isListable(model, mainField)) {
2569
+ const isMainFieldListable = isListable(model, mainField);
2570
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2571
+ if (!isMainFieldListable || !canReadMainField) {
2286
2572
  return "id";
2287
2573
  }
2288
- if (permissionChecker2.cannot.read(null, mainField)) {
2289
- if (model.uid === "plugin::users-permissions.role") {
2290
- const userPermissionChecker = getService$1("permission-checker").create({
2291
- userAbility,
2292
- model: "plugin::users-permissions.user"
2293
- });
2294
- if (userPermissionChecker.can.read()) {
2295
- return "name";
2296
- }
2297
- }
2298
- return "id";
2574
+ if (model.uid === "plugin::users-permissions.role") {
2575
+ return "name";
2299
2576
  }
2300
2577
  return mainField;
2301
2578
  };
2302
- const addStatusToRelations = async (uid2, relations2) => {
2303
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2579
+ const addStatusToRelations = async (targetUid, relations2) => {
2580
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
2581
+ return relations2;
2582
+ }
2583
+ const documentMetadata2 = getService$2("document-metadata");
2584
+ if (!relations2.length) {
2304
2585
  return relations2;
2305
2586
  }
2306
- const documentMetadata2 = getService$1("document-metadata");
2307
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2587
+ const firstRelation = relations2[0];
2588
+ const filters = {
2589
+ documentId: { $in: relations2.map((r) => r.documentId) },
2590
+ // NOTE: find the "opposite" status
2591
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2592
+ };
2593
+ const availableStatus = await strapi.query(targetUid).findMany({
2594
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2595
+ filters
2596
+ });
2308
2597
  return relations2.map((relation) => {
2309
- const availableStatuses = documentsAvailableStatus.filter(
2310
- (availableDocument) => availableDocument.documentId === relation.documentId
2598
+ const availableStatuses = availableStatus.filter(
2599
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2311
2600
  );
2312
2601
  return {
2313
2602
  ...relation,
@@ -2328,11 +2617,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2328
2617
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2329
2618
  const isSourceLocalized = isLocalized(sourceModel);
2330
2619
  const isTargetLocalized = isLocalized(targetModel);
2331
- let validatedLocale = locale;
2332
- if (!targetModel || !isTargetLocalized)
2333
- validatedLocale = void 0;
2334
2620
  return {
2335
- locale: validatedLocale,
2621
+ locale,
2336
2622
  isSourceLocalized,
2337
2623
  isTargetLocalized
2338
2624
  };
@@ -2341,8 +2627,7 @@ const validateStatus = (sourceUid, status) => {
2341
2627
  const sourceModel = strapi.getModel(sourceUid);
2342
2628
  const isDP = strapiUtils.contentTypes.hasDraftAndPublish;
2343
2629
  const isSourceDP = isDP(sourceModel);
2344
- if (!isSourceDP)
2345
- return { status: void 0 };
2630
+ if (!isSourceDP) return { status: void 0 };
2346
2631
  switch (status) {
2347
2632
  case "published":
2348
2633
  return { status: "published" };
@@ -2372,7 +2657,7 @@ const relations = {
2372
2657
  ctx.request?.query?.locale
2373
2658
  );
2374
2659
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2375
- const permissionChecker2 = getService$1("permission-checker").create({
2660
+ const permissionChecker2 = getService$2("permission-checker").create({
2376
2661
  userAbility,
2377
2662
  model
2378
2663
  });
@@ -2397,7 +2682,7 @@ const relations = {
2397
2682
  where.id = id;
2398
2683
  }
2399
2684
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2400
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2685
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2401
2686
  const currentEntity = await strapi.db.query(model).findOne({
2402
2687
  where,
2403
2688
  populate
@@ -2412,7 +2697,7 @@ const relations = {
2412
2697
  }
2413
2698
  entryId = currentEntity.id;
2414
2699
  }
2415
- const modelConfig = isComponent2 ? await getService$1("components").findConfiguration(sourceSchema) : await getService$1("content-types").findConfiguration(sourceSchema);
2700
+ const modelConfig = isComponent2 ? await getService$2("components").findConfiguration(sourceSchema) : await getService$2("content-types").findConfiguration(sourceSchema);
2416
2701
  const targetSchema = strapi.getModel(targetUid);
2417
2702
  const mainField = fp.flow(
2418
2703
  fp.prop(`metadatas.${targetField}.edit.mainField`),
@@ -2435,7 +2720,7 @@ const relations = {
2435
2720
  attribute,
2436
2721
  fieldsToSelect,
2437
2722
  mainField,
2438
- source: { schema: sourceSchema },
2723
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2439
2724
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2440
2725
  sourceSchema,
2441
2726
  targetSchema,
@@ -2457,7 +2742,8 @@ const relations = {
2457
2742
  fieldsToSelect,
2458
2743
  mainField,
2459
2744
  source: {
2460
- schema: { uid: sourceUid, modelType: sourceModelType }
2745
+ schema: { uid: sourceUid, modelType: sourceModelType },
2746
+ isLocalized: isSourceLocalized
2461
2747
  },
2462
2748
  target: {
2463
2749
  schema: { uid: targetUid },
@@ -2465,7 +2751,7 @@ const relations = {
2465
2751
  }
2466
2752
  } = await this.extractAndValidateRequestInfo(ctx, id);
2467
2753
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2468
- const permissionChecker2 = getService$1("permission-checker").create({
2754
+ const permissionChecker2 = getService$2("permission-checker").create({
2469
2755
  userAbility: ctx.state.userAbility,
2470
2756
  model: targetUid
2471
2757
  });
@@ -2495,12 +2781,16 @@ const relations = {
2495
2781
  } else {
2496
2782
  where.id = id;
2497
2783
  }
2498
- if (status) {
2499
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2784
+ const publishedAt = getPublishedAtClause(status, targetUid);
2785
+ if (!fp.isEmpty(publishedAt)) {
2786
+ where[`${alias}.published_at`] = publishedAt;
2500
2787
  }
2501
- if (filterByLocale) {
2788
+ if (isTargetLocalized && locale) {
2502
2789
  where[`${alias}.locale`] = locale;
2503
2790
  }
2791
+ if (isSourceLocalized && locale) {
2792
+ where.locale = locale;
2793
+ }
2504
2794
  if ((idsToInclude?.length ?? 0) !== 0) {
2505
2795
  where[`${alias}.id`].$notIn = idsToInclude;
2506
2796
  }
@@ -2518,7 +2808,8 @@ const relations = {
2518
2808
  id: { $notIn: fp.uniq(idsToOmit) }
2519
2809
  });
2520
2810
  }
2521
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2811
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2812
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2522
2813
  ctx.body = {
2523
2814
  ...res,
2524
2815
  results: await addStatusToRelations(targetUid, res.results)
@@ -2533,29 +2824,39 @@ const relations = {
2533
2824
  attribute,
2534
2825
  targetField,
2535
2826
  fieldsToSelect,
2536
- source: {
2537
- schema: { uid: sourceUid }
2538
- },
2539
- target: {
2540
- schema: { uid: targetUid }
2541
- }
2827
+ status,
2828
+ source: { schema: sourceSchema },
2829
+ target: { schema: targetSchema }
2542
2830
  } = await this.extractAndValidateRequestInfo(ctx, id);
2543
- const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2831
+ const { uid: sourceUid } = sourceSchema;
2832
+ const { uid: targetUid } = targetSchema;
2833
+ const permissionQuery = await getService$2("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2544
2834
  const dbQuery = strapi.db.query(sourceUid);
2545
2835
  const loadRelations = strapiUtils.relations.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2836
+ const filters = {};
2837
+ if (sourceSchema?.options?.draftAndPublish) {
2838
+ if (targetSchema?.options?.draftAndPublish) {
2839
+ if (status === "published") {
2840
+ filters.publishedAt = { $notNull: true };
2841
+ } else {
2842
+ filters.publishedAt = { $null: true };
2843
+ }
2844
+ }
2845
+ } else if (targetSchema?.options?.draftAndPublish) {
2846
+ filters.publishedAt = { $null: true };
2847
+ }
2546
2848
  const res = await loadRelations({ id: entryId }, targetField, {
2547
- select: ["id", "documentId", "locale", "publishedAt"],
2849
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2548
2850
  ordering: "desc",
2549
2851
  page: ctx.request.query.page,
2550
- pageSize: ctx.request.query.pageSize
2852
+ pageSize: ctx.request.query.pageSize,
2853
+ filters
2551
2854
  });
2552
2855
  const loadedIds = res.results.map((item) => item.id);
2553
2856
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2554
2857
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2555
2858
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2556
- ordering: "desc",
2557
- page: ctx.request.query.page,
2558
- pageSize: ctx.request.query.pageSize
2859
+ ordering: "desc"
2559
2860
  });
2560
2861
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2561
2862
  ctx.body = {
@@ -2570,10 +2871,10 @@ const relations = {
2570
2871
  }
2571
2872
  };
2572
2873
  const buildPopulateFromQuery = async (query, model) => {
2573
- return getService$1("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2874
+ return getService$2("populate-builder")(model).populateFromQuery(query).populateDeep(Infinity).countRelations().build();
2574
2875
  };
2575
2876
  const findDocument = async (query, uid2, opts = {}) => {
2576
- const documentManager2 = getService$1("document-manager");
2877
+ const documentManager2 = getService$2("document-manager");
2577
2878
  const populate = await buildPopulateFromQuery(query, uid2);
2578
2879
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2579
2880
  };
@@ -2581,13 +2882,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
2581
2882
  const { user, userAbility } = ctx.state;
2582
2883
  const { model } = ctx.params;
2583
2884
  const { body, query } = ctx.request;
2584
- const documentManager2 = getService$1("document-manager");
2585
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2885
+ const documentManager2 = getService$2("document-manager");
2886
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2586
2887
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2587
2888
  throw new strapiUtils.errors.ForbiddenError();
2588
2889
  }
2589
2890
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2590
- const { locale } = await getDocumentLocaleAndStatus(body);
2891
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2591
2892
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2592
2893
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2593
2894
  // Find the first document to check if it exists
@@ -2623,12 +2924,12 @@ const singleTypes = {
2623
2924
  const { userAbility } = ctx.state;
2624
2925
  const { model } = ctx.params;
2625
2926
  const { query = {} } = ctx.request;
2626
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2927
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2627
2928
  if (permissionChecker2.cannot.read()) {
2628
2929
  return ctx.forbidden();
2629
2930
  }
2630
2931
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2631
- const { locale, status } = await getDocumentLocaleAndStatus(query);
2932
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2632
2933
  const version = await findDocument(permissionQuery, model, { locale, status });
2633
2934
  if (!version) {
2634
2935
  if (permissionChecker2.cannot.create()) {
@@ -2642,7 +2943,7 @@ const singleTypes = {
2642
2943
  permissionChecker2,
2643
2944
  model,
2644
2945
  // @ts-expect-error - fix types
2645
- { id: document.documentId, locale, publishedAt: null },
2946
+ { documentId: document.documentId, locale, publishedAt: null },
2646
2947
  { availableLocales: true, availableStatus: false }
2647
2948
  );
2648
2949
  ctx.body = { data: {}, meta };
@@ -2657,7 +2958,7 @@ const singleTypes = {
2657
2958
  async createOrUpdate(ctx) {
2658
2959
  const { userAbility } = ctx.state;
2659
2960
  const { model } = ctx.params;
2660
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2661
2962
  const document = await createOrUpdateDocument(ctx);
2662
2963
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2663
2964
  ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
@@ -2666,14 +2967,14 @@ const singleTypes = {
2666
2967
  const { userAbility } = ctx.state;
2667
2968
  const { model } = ctx.params;
2668
2969
  const { query = {} } = ctx.request;
2669
- const documentManager2 = getService$1("document-manager");
2670
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2970
+ const documentManager2 = getService$2("document-manager");
2971
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2671
2972
  if (permissionChecker2.cannot.delete()) {
2672
2973
  return ctx.forbidden();
2673
2974
  }
2674
2975
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2675
2976
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2676
- const { locale } = await getDocumentLocaleAndStatus(query);
2977
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2677
2978
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2678
2979
  populate,
2679
2980
  locale
@@ -2695,8 +2996,8 @@ const singleTypes = {
2695
2996
  const { userAbility } = ctx.state;
2696
2997
  const { model } = ctx.params;
2697
2998
  const { query = {} } = ctx.request;
2698
- const documentManager2 = getService$1("document-manager");
2699
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2999
+ const documentManager2 = getService$2("document-manager");
3000
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2700
3001
  if (permissionChecker2.cannot.publish()) {
2701
3002
  return ctx.forbidden();
2702
3003
  }
@@ -2710,7 +3011,7 @@ const singleTypes = {
2710
3011
  if (permissionChecker2.cannot.publish(document)) {
2711
3012
  throw new strapiUtils.errors.ForbiddenError();
2712
3013
  }
2713
- const { locale } = await getDocumentLocaleAndStatus(document);
3014
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2714
3015
  const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2715
3016
  return publishResult.at(0);
2716
3017
  });
@@ -2724,8 +3025,8 @@ const singleTypes = {
2724
3025
  body: { discardDraft, ...body },
2725
3026
  query = {}
2726
3027
  } = ctx.request;
2727
- const documentManager2 = getService$1("document-manager");
2728
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3028
+ const documentManager2 = getService$2("document-manager");
3029
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2729
3030
  if (permissionChecker2.cannot.unpublish()) {
2730
3031
  return ctx.forbidden();
2731
3032
  }
@@ -2733,7 +3034,7 @@ const singleTypes = {
2733
3034
  return ctx.forbidden();
2734
3035
  }
2735
3036
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2736
- const { locale } = await getDocumentLocaleAndStatus(body);
3037
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2737
3038
  const document = await findDocument(sanitizedQuery, model, { locale });
2738
3039
  if (!document) {
2739
3040
  return ctx.notFound();
@@ -2759,13 +3060,13 @@ const singleTypes = {
2759
3060
  const { userAbility } = ctx.state;
2760
3061
  const { model } = ctx.params;
2761
3062
  const { body, query = {} } = ctx.request;
2762
- const documentManager2 = getService$1("document-manager");
2763
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
3063
+ const documentManager2 = getService$2("document-manager");
3064
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2764
3065
  if (permissionChecker2.cannot.discard()) {
2765
3066
  return ctx.forbidden();
2766
3067
  }
2767
3068
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2768
- const { locale } = await getDocumentLocaleAndStatus(body);
3069
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2769
3070
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2770
3071
  if (!document) {
2771
3072
  return ctx.notFound();
@@ -2783,9 +3084,9 @@ const singleTypes = {
2783
3084
  const { userAbility } = ctx.state;
2784
3085
  const { model } = ctx.params;
2785
3086
  const { query } = ctx.request;
2786
- const documentManager2 = getService$1("document-manager");
2787
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2788
- const { locale } = await getDocumentLocaleAndStatus(query);
3087
+ const documentManager2 = getService$2("document-manager");
3088
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
3089
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2789
3090
  if (permissionChecker2.cannot.read()) {
2790
3091
  return ctx.forbidden();
2791
3092
  }
@@ -2806,9 +3107,9 @@ const uid$1 = {
2806
3107
  async generateUID(ctx) {
2807
3108
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2808
3109
  const { query = {} } = ctx.request;
2809
- const { locale } = await getDocumentLocaleAndStatus(query);
3110
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2810
3111
  await validateUIDField(contentTypeUID, field);
2811
- const uidService = getService$1("uid");
3112
+ const uidService = getService$2("uid");
2812
3113
  ctx.body = {
2813
3114
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2814
3115
  };
@@ -2818,9 +3119,9 @@ const uid$1 = {
2818
3119
  ctx.request.body
2819
3120
  );
2820
3121
  const { query = {} } = ctx.request;
2821
- const { locale } = await getDocumentLocaleAndStatus(query);
3122
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2822
3123
  await validateUIDField(contentTypeUID, field);
2823
- const uidService = getService$1("uid");
3124
+ const uidService = getService$2("uid");
2824
3125
  const isAvailable = await uidService.checkUIDAvailability({
2825
3126
  contentTypeUID,
2826
3127
  field,
@@ -2841,7 +3142,8 @@ const controllers = {
2841
3142
  relations,
2842
3143
  "single-types": singleTypes,
2843
3144
  uid: uid$1,
2844
- ...history.controllers ? history.controllers : {}
3145
+ ...history.controllers ? history.controllers : {},
3146
+ ...preview.controllers ? preview.controllers : {}
2845
3147
  };
2846
3148
  const keys = {
2847
3149
  CONFIGURATION: "configuration"
@@ -2970,18 +3272,15 @@ async function syncMetadatas(configuration, schema) {
2970
3272
  ___default.default.set(updatedMeta, ["list", "searchable"], false);
2971
3273
  ___default.default.set(acc, [key], updatedMeta);
2972
3274
  }
2973
- if (!___default.default.has(edit, "mainField"))
2974
- return acc;
3275
+ if (!___default.default.has(edit, "mainField")) return acc;
2975
3276
  if (!isRelation$1(attr)) {
2976
3277
  ___default.default.set(updatedMeta, "edit", ___default.default.omit(edit, ["mainField"]));
2977
3278
  ___default.default.set(acc, [key], updatedMeta);
2978
3279
  return acc;
2979
3280
  }
2980
- if (edit.mainField === "id")
2981
- return acc;
3281
+ if (edit.mainField === "id") return acc;
2982
3282
  const targetSchema = getTargetSchema(attr.targetModel);
2983
- if (!targetSchema)
2984
- return acc;
3283
+ if (!targetSchema) return acc;
2985
3284
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2986
3285
  ___default.default.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2987
3286
  ___default.default.set(acc, [key], updatedMeta);
@@ -2992,12 +3291,12 @@ async function syncMetadatas(configuration, schema) {
2992
3291
  return ___default.default.assign(metasWithDefaults, updatedMetas);
2993
3292
  }
2994
3293
  const getTargetSchema = (targetModel) => {
2995
- return getService$1("content-types").findContentType(targetModel);
3294
+ return getService$2("content-types").findContentType(targetModel);
2996
3295
  };
2997
3296
  const DEFAULT_LIST_LENGTH = 4;
2998
3297
  const MAX_ROW_SIZE = 12;
2999
3298
  const isAllowedFieldSize = (type, size) => {
3000
- const { getFieldSize } = getService$1("field-sizes");
3299
+ const { getFieldSize } = getService$2("field-sizes");
3001
3300
  const fieldSize = getFieldSize(type);
3002
3301
  if (!fieldSize.isResizable && size !== fieldSize.default) {
3003
3302
  return false;
@@ -3005,7 +3304,7 @@ const isAllowedFieldSize = (type, size) => {
3005
3304
  return size <= MAX_ROW_SIZE;
3006
3305
  };
3007
3306
  const getDefaultFieldSize = (attribute) => {
3008
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3307
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
3009
3308
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
3010
3309
  };
3011
3310
  async function createDefaultLayouts(schema) {
@@ -3026,8 +3325,7 @@ function createDefaultEditLayout(schema) {
3026
3325
  return appendToEditLayout([], keys2, schema);
3027
3326
  }
3028
3327
  function syncLayouts(configuration, schema) {
3029
- if (___default.default.isEmpty(configuration.layouts))
3030
- return createDefaultLayouts(schema);
3328
+ if (___default.default.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
3031
3329
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
3032
3330
  let cleanList = list.filter((attr) => isListable(schema, attr));
3033
3331
  const cleanEditRelations = editRelations.filter(
@@ -3038,9 +3336,8 @@ function syncLayouts(configuration, schema) {
3038
3336
  for (const row of edit) {
3039
3337
  const newRow = [];
3040
3338
  for (const el of row) {
3041
- if (!hasEditableAttribute(schema, el.name))
3042
- continue;
3043
- const { hasFieldSize } = getService$1("field-sizes");
3339
+ if (!hasEditableAttribute(schema, el.name)) continue;
3340
+ const { hasFieldSize } = getService$2("field-sizes");
3044
3341
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
3045
3342
  if (!isAllowedFieldSize(fieldType, el.size)) {
3046
3343
  elementsToReAppend.push(el.name);
@@ -3070,8 +3367,7 @@ function syncLayouts(configuration, schema) {
3070
3367
  };
3071
3368
  }
3072
3369
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
3073
- if (keysToAppend.length === 0)
3074
- return layout;
3370
+ if (keysToAppend.length === 0) return layout;
3075
3371
  let currentRowIndex = Math.max(layout.length - 1, 0);
3076
3372
  if (!layout[currentRowIndex]) {
3077
3373
  layout[currentRowIndex] = [];
@@ -3180,17 +3476,17 @@ const configurationService$1 = createConfigurationService({
3180
3476
  isComponent: true,
3181
3477
  prefix: STORE_KEY_PREFIX,
3182
3478
  getModels() {
3183
- const { toContentManagerModel } = getService$1("data-mapper");
3479
+ const { toContentManagerModel } = getService$2("data-mapper");
3184
3480
  return fp.mapValues(toContentManagerModel, strapi.components);
3185
3481
  }
3186
3482
  });
3187
3483
  const components = ({ strapi: strapi2 }) => ({
3188
3484
  findAllComponents() {
3189
- const { toContentManagerModel } = getService$1("data-mapper");
3485
+ const { toContentManagerModel } = getService$2("data-mapper");
3190
3486
  return Object.values(strapi2.components).map(toContentManagerModel);
3191
3487
  },
3192
3488
  findComponent(uid2) {
3193
- const { toContentManagerModel } = getService$1("data-mapper");
3489
+ const { toContentManagerModel } = getService$2("data-mapper");
3194
3490
  const component = strapi2.components[uid2];
3195
3491
  return fp.isNil(component) ? component : toContentManagerModel(component);
3196
3492
  },
@@ -3241,17 +3537,17 @@ const configurationService = createConfigurationService({
3241
3537
  storeUtils,
3242
3538
  prefix: "content_types",
3243
3539
  getModels() {
3244
- const { toContentManagerModel } = getService$1("data-mapper");
3540
+ const { toContentManagerModel } = getService$2("data-mapper");
3245
3541
  return fp.mapValues(toContentManagerModel, strapi.contentTypes);
3246
3542
  }
3247
3543
  });
3248
3544
  const service = ({ strapi: strapi2 }) => ({
3249
3545
  findAllContentTypes() {
3250
- const { toContentManagerModel } = getService$1("data-mapper");
3546
+ const { toContentManagerModel } = getService$2("data-mapper");
3251
3547
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3252
3548
  },
3253
3549
  findContentType(uid2) {
3254
- const { toContentManagerModel } = getService$1("data-mapper");
3550
+ const { toContentManagerModel } = getService$2("data-mapper");
3255
3551
  const contentType = strapi2.contentTypes[uid2];
3256
3552
  return fp.isNil(contentType) ? contentType : toContentManagerModel(contentType);
3257
3553
  },
@@ -3280,7 +3576,7 @@ const service = ({ strapi: strapi2 }) => ({
3280
3576
  return this.findConfiguration(contentType);
3281
3577
  },
3282
3578
  findComponentsConfigurations(contentType) {
3283
- return getService$1("components").findComponentsConfigurations(contentType);
3579
+ return getService$2("components").findComponentsConfigurations(contentType);
3284
3580
  },
3285
3581
  syncConfigurations() {
3286
3582
  return configurationService.syncConfigurations();
@@ -3461,12 +3757,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3461
3757
  ability: userAbility,
3462
3758
  model
3463
3759
  });
3464
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3760
+ const { actionProvider } = strapi2.service("admin::permission");
3761
+ const toSubject = (entity) => {
3762
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3763
+ };
3465
3764
  const can = (action, entity, field) => {
3466
- return userAbility.can(action, toSubject(entity), field);
3765
+ const subject = toSubject(entity);
3766
+ const aliases = actionProvider.unstable_aliases(action, model);
3767
+ return (
3768
+ // Test the original action to see if it passes
3769
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3770
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3771
+ );
3467
3772
  };
3468
3773
  const cannot = (action, entity, field) => {
3469
- return userAbility.cannot(action, toSubject(entity), field);
3774
+ const subject = toSubject(entity);
3775
+ const aliases = actionProvider.unstable_aliases(action, model);
3776
+ return (
3777
+ // Test both the original action
3778
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3779
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3780
+ );
3470
3781
  };
3471
3782
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3472
3783
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3537,7 +3848,7 @@ const permission = ({ strapi: strapi2 }) => ({
3537
3848
  return userAbility.can(action);
3538
3849
  },
3539
3850
  async registerPermissions() {
3540
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3851
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3541
3852
  const contentTypesUids = displayedContentTypes.map(fp.prop("uid"));
3542
3853
  const actions = [
3543
3854
  {
@@ -3622,6 +3933,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3622
3933
  if (initialPopulate) {
3623
3934
  return initialPopulate;
3624
3935
  }
3936
+ if (attributeName === "localizations") {
3937
+ const validationPopulate = getPopulateForValidation(model.uid);
3938
+ return {
3939
+ populate: validationPopulate.populate
3940
+ };
3941
+ }
3625
3942
  if (!isVisibleAttribute$1(model, attributeName)) {
3626
3943
  return true;
3627
3944
  }
@@ -3681,6 +3998,9 @@ const getDeepPopulate = (uid2, {
3681
3998
  return {};
3682
3999
  }
3683
4000
  const model = strapi.getModel(uid2);
4001
+ if (!model) {
4002
+ return {};
4003
+ }
3684
4004
  return Object.keys(model.attributes).reduce(
3685
4005
  (populateAcc, attributeName) => fp.merge(
3686
4006
  populateAcc,
@@ -3700,40 +4020,46 @@ const getDeepPopulate = (uid2, {
3700
4020
  {}
3701
4021
  );
3702
4022
  };
3703
- const getValidatableFieldsPopulate = (uid2, {
3704
- initialPopulate = {},
3705
- countMany = false,
3706
- countOne = false,
3707
- maxLevel = Infinity
3708
- } = {}, level = 1) => {
3709
- if (level > maxLevel) {
4023
+ const getPopulateForValidation = (uid2) => {
4024
+ const model = strapi.getModel(uid2);
4025
+ if (!model) {
3710
4026
  return {};
3711
4027
  }
3712
- const model = strapi.getModel(uid2);
3713
4028
  return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
3714
- if (!getDoesAttributeRequireValidation(attribute)) {
4029
+ if (isScalarAttribute(attribute)) {
4030
+ if (getDoesAttributeRequireValidation(attribute)) {
4031
+ populateAcc.fields = populateAcc.fields || [];
4032
+ populateAcc.fields.push(attributeName);
4033
+ }
3715
4034
  return populateAcc;
3716
4035
  }
3717
- if (isScalarAttribute(attribute)) {
3718
- return fp.merge(populateAcc, {
3719
- [attributeName]: true
3720
- });
4036
+ if (isComponent(attribute)) {
4037
+ const component = attribute.component;
4038
+ const componentResult = getPopulateForValidation(component);
4039
+ if (Object.keys(componentResult).length > 0) {
4040
+ populateAcc.populate = populateAcc.populate || {};
4041
+ populateAcc.populate[attributeName] = componentResult;
4042
+ }
4043
+ return populateAcc;
3721
4044
  }
3722
- return fp.merge(
3723
- populateAcc,
3724
- getPopulateFor(
3725
- attributeName,
3726
- model,
3727
- {
3728
- // @ts-expect-error - improve types
3729
- initialPopulate: initialPopulate?.[attributeName],
3730
- countMany,
3731
- countOne,
3732
- maxLevel
4045
+ if (isDynamicZone(attribute)) {
4046
+ const components2 = attribute.components;
4047
+ const componentsResult = (components2 || []).reduce(
4048
+ (acc, componentUID) => {
4049
+ const componentResult = getPopulateForValidation(componentUID);
4050
+ if (Object.keys(componentResult).length > 0) {
4051
+ acc[componentUID] = componentResult;
4052
+ }
4053
+ return acc;
3733
4054
  },
3734
- level
3735
- )
3736
- );
4055
+ {}
4056
+ );
4057
+ if (Object.keys(componentsResult).length > 0) {
4058
+ populateAcc.populate = populateAcc.populate || {};
4059
+ populateAcc.populate[attributeName] = { on: componentsResult };
4060
+ }
4061
+ }
4062
+ return populateAcc;
3737
4063
  }, {});
3738
4064
  };
3739
4065
  const getDeepPopulateDraftCount = (uid2) => {
@@ -3743,6 +4069,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3743
4069
  const attribute = model.attributes[attributeName];
3744
4070
  switch (attribute.type) {
3745
4071
  case "relation": {
4072
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
4073
+ if (isMorphRelation) {
4074
+ break;
4075
+ }
3746
4076
  if (isVisibleAttribute$1(model, attributeName)) {
3747
4077
  populateAcc[attributeName] = {
3748
4078
  count: true,
@@ -3809,7 +4139,7 @@ const getQueryPopulate = async (uid2, query) => {
3809
4139
  return populateQuery;
3810
4140
  };
3811
4141
  const buildDeepPopulate = (uid2) => {
3812
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4142
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3813
4143
  };
3814
4144
  const populateBuilder = (uid2) => {
3815
4145
  let getInitialPopulate = async () => {
@@ -3971,7 +4301,6 @@ const AVAILABLE_LOCALES_FIELDS = [
3971
4301
  "locale",
3972
4302
  "updatedAt",
3973
4303
  "createdAt",
3974
- "status",
3975
4304
  "publishedAt",
3976
4305
  "documentId"
3977
4306
  ];
@@ -3992,34 +4321,20 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3992
4321
  /**
3993
4322
  * Returns available locales of a document for the current status
3994
4323
  */
3995
- async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
4324
+ async getAvailableLocales(uid2, version, allVersions) {
3996
4325
  const versionsByLocale = fp.groupBy("locale", allVersions);
3997
- delete versionsByLocale[version.locale];
4326
+ if (version.locale) {
4327
+ delete versionsByLocale[version.locale];
4328
+ }
3998
4329
  const model = strapi2.getModel(uid2);
3999
- const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
4000
- const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
4001
- ({ key }, { remove }) => {
4002
- if (keysToKeep.includes(key)) {
4003
- return;
4004
- }
4005
- remove(key);
4006
- },
4007
- { schema: model, getModel: strapi2.getModel.bind(strapi2) },
4008
- // @ts-expect-error fix types DocumentVersion incompatible with Data
4009
- localeVersion
4010
- );
4011
4330
  const mappingResult = await strapiUtils.async.map(
4012
4331
  Object.values(versionsByLocale),
4013
4332
  async (localeVersions) => {
4014
- const mappedLocaleVersions = await strapiUtils.async.map(
4015
- localeVersions,
4016
- traversalFunction
4017
- );
4018
4333
  if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
4019
- return mappedLocaleVersions[0];
4334
+ return localeVersions[0];
4020
4335
  }
4021
- const draftVersion = mappedLocaleVersions.find((v) => v.publishedAt === null);
4022
- const otherVersions = mappedLocaleVersions.filter((v) => v.id !== draftVersion?.id);
4336
+ const draftVersion = localeVersions.find((v) => v.publishedAt === null);
4337
+ const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
4023
4338
  if (!draftVersion) {
4024
4339
  return;
4025
4340
  }
@@ -4041,8 +4356,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4041
4356
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
4042
4357
  return matchLocale && matchStatus;
4043
4358
  });
4044
- if (!availableStatus)
4045
- return availableStatus;
4359
+ if (!availableStatus) return availableStatus;
4046
4360
  return fp.pick(AVAILABLE_STATUS_FIELDS, availableStatus);
4047
4361
  },
4048
4362
  /**
@@ -4052,18 +4366,19 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4052
4366
  * @returns
4053
4367
  */
4054
4368
  async getManyAvailableStatus(uid2, documents) {
4055
- if (!documents.length)
4056
- return [];
4369
+ if (!documents.length) return [];
4057
4370
  const status = documents[0].publishedAt !== null ? "published" : "draft";
4058
- const locale = documents[0]?.locale;
4059
- const otherStatus = status === "published" ? "draft" : "published";
4060
- return strapi2.documents(uid2).findMany({
4061
- filters: {
4062
- documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) }
4063
- },
4064
- status: otherStatus,
4065
- locale,
4066
- fields: ["documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4371
+ const locales = documents.map((d) => d.locale).filter(Boolean);
4372
+ const where = {
4373
+ documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },
4374
+ publishedAt: { $null: status === "published" }
4375
+ };
4376
+ if (locales.length) {
4377
+ where.locale = { $in: locales };
4378
+ }
4379
+ return strapi2.query(uid2).findMany({
4380
+ where,
4381
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"]
4067
4382
  });
4068
4383
  },
4069
4384
  getStatus(version, otherDocumentStatuses) {
@@ -4080,10 +4395,8 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4080
4395
  } else if (otherVersion) {
4081
4396
  draftVersion = otherVersion;
4082
4397
  }
4083
- if (!draftVersion)
4084
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4085
- if (!publishedVersion)
4086
- return CONTENT_MANAGER_STATUS.DRAFT;
4398
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4399
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4087
4400
  const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4088
4401
  return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
4089
4402
  },
@@ -4091,11 +4404,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4091
4404
  // We could refactor this so the locales are only loaded when they're
4092
4405
  // needed. e.g. in the bulk locale action modal.
4093
4406
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
4094
- const populate = getValidatableFieldsPopulate(uid2);
4095
- const versions = await strapi2.db.query(uid2).findMany({
4096
- where: { documentId: version.documentId },
4407
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4408
+ const params = {
4097
4409
  populate: {
4098
- // Populate only fields that require validation for bulk locale actions
4099
4410
  ...populate,
4100
4411
  // NOTE: creator fields are selected in this way to avoid exposing sensitive data
4101
4412
  createdBy: {
@@ -4104,9 +4415,15 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4104
4415
  updatedBy: {
4105
4416
  select: ["id", "firstname", "lastname", "email"]
4106
4417
  }
4418
+ },
4419
+ fields: fp.uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4420
+ filters: {
4421
+ documentId: version.documentId
4107
4422
  }
4108
- });
4109
- const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions, Object.keys(populate)) : [];
4423
+ };
4424
+ const dbParams = strapi2.get("query-params").transform(uid2, params);
4425
+ const versions = await strapi2.db.query(uid2).findMany(dbParams);
4426
+ const availableLocalesResult = availableLocales ? await this.getAvailableLocales(uid2, version, versions) : [];
4110
4427
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
4111
4428
  return {
4112
4429
  availableLocales: availableLocalesResult,
@@ -4120,13 +4437,29 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4120
4437
  */
4121
4438
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4122
4439
  if (!document) {
4123
- return document;
4440
+ return {
4441
+ data: document,
4442
+ meta: {
4443
+ availableLocales: [],
4444
+ availableStatus: []
4445
+ }
4446
+ };
4124
4447
  }
4125
4448
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4126
4449
  if (!hasDraftAndPublish) {
4127
4450
  opts.availableStatus = false;
4128
4451
  }
4129
4452
  const meta = await this.getMetadata(uid2, document, opts);
4453
+ if (document.localizations) {
4454
+ const otherStatus = await this.getManyAvailableStatus(uid2, document.localizations);
4455
+ document.localizations = document.localizations.map((d) => {
4456
+ const status = otherStatus.find((s) => s.documentId === d.documentId);
4457
+ return {
4458
+ ...d,
4459
+ status: this.getStatus(d, status ? [status] : [])
4460
+ };
4461
+ });
4462
+ }
4130
4463
  return {
4131
4464
  data: {
4132
4465
  ...document,
@@ -4228,10 +4561,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4228
4561
  async clone(id, body, uid2) {
4229
4562
  const populate = await buildDeepPopulate(uid2);
4230
4563
  const params = {
4231
- data: {
4232
- ...omitIdField(body),
4233
- [PUBLISHED_AT_ATTRIBUTE]: null
4234
- },
4564
+ data: omitIdField(body),
4235
4565
  populate
4236
4566
  };
4237
4567
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4347,7 +4677,8 @@ const services = {
4347
4677
  permission,
4348
4678
  "populate-builder": populateBuilder$1,
4349
4679
  uid,
4350
- ...history.services ? history.services : {}
4680
+ ...history.services ? history.services : {},
4681
+ ...preview.services ? preview.services : {}
4351
4682
  };
4352
4683
  const index = () => {
4353
4684
  return {