@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.19d775295eb622de3e659110caf22fcd2cd5d10d

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 (264) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs → ComponentConfigurationPage-B_99pmC0.mjs} +4 -4
  7. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-B_99pmC0.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-NeMPjY5M.js} +5 -6
  9. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-NeMPjY5M.js.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-CRbtQEUV.js} +9 -4
  11. package/dist/_chunks/ComponentIcon-CRbtQEUV.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs → EditConfigurationPage-B0kNlNoj.mjs} +4 -4
  15. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-B0kNlNoj.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-n7_xHayb.js} +5 -6
  17. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-n7_xHayb.js.map} +1 -1
  18. package/dist/_chunks/EditViewPage-BT7Achc-.js +209 -0
  19. package/dist/_chunks/EditViewPage-BT7Achc-.js.map +1 -0
  20. package/dist/_chunks/EditViewPage-DYXZs4_2.mjs +191 -0
  21. package/dist/_chunks/EditViewPage-DYXZs4_2.mjs.map +1 -0
  22. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  23. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  24. package/dist/_chunks/{Form-CQ67ZifP.js → Form-BRmk2Dp3.js} +68 -49
  25. package/dist/_chunks/Form-BRmk2Dp3.js.map +1 -0
  26. package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-D3paRF1F.mjs} +67 -46
  27. package/dist/_chunks/Form-D3paRF1F.mjs.map +1 -0
  28. package/dist/_chunks/{History-BLEnudTX.js → History-BQpDoOu8.js} +211 -148
  29. package/dist/_chunks/History-BQpDoOu8.js.map +1 -0
  30. package/dist/_chunks/{History-DKhZAPcK.mjs → History-CzQbTOwa.mjs} +204 -139
  31. package/dist/_chunks/History-CzQbTOwa.mjs.map +1 -0
  32. package/dist/_chunks/{Field-kVFO4ZKB.mjs → Input-ww3KFYZr.mjs} +1996 -1730
  33. package/dist/_chunks/Input-ww3KFYZr.mjs.map +1 -0
  34. package/dist/_chunks/{Field-kq1c2TF1.js → Input-yM6HnyQa.js} +2035 -1770
  35. package/dist/_chunks/Input-yM6HnyQa.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-B6NsS-0m.js} +72 -63
  37. package/dist/_chunks/ListConfigurationPage-B6NsS-0m.js.map +1 -0
  38. package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-Bbw8w5cS.mjs} +68 -57
  39. package/dist/_chunks/ListConfigurationPage-Bbw8w5cS.mjs.map +1 -0
  40. package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-DnOP55pM.mjs} +179 -160
  41. package/dist/_chunks/ListViewPage-DnOP55pM.mjs.map +1 -0
  42. package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-Dt8OUTwO.js} +183 -165
  43. package/dist/_chunks/ListViewPage-Dt8OUTwO.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-CXKXHNMa.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-CXKXHNMa.mjs.map +1 -0
  46. package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-Dgm-uj-6.js} +3 -3
  47. package/dist/_chunks/NoContentTypePage-Dgm-uj-6.js.map +1 -0
  48. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-CLbU5SOt.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-CLbU5SOt.js.map} +1 -1
  50. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-kaj1rPiW.mjs} +2 -2
  51. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-kaj1rPiW.mjs.map} +1 -1
  52. package/dist/_chunks/Preview-Bieh13Ro.mjs +287 -0
  53. package/dist/_chunks/Preview-Bieh13Ro.mjs.map +1 -0
  54. package/dist/_chunks/Preview-CbXHXqBg.js +305 -0
  55. package/dist/_chunks/Preview-CbXHXqBg.js.map +1 -0
  56. package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-7rWJcZ3_.mjs} +138 -94
  57. package/dist/_chunks/Relations-7rWJcZ3_.mjs.map +1 -0
  58. package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-CvifV6Y6.js} +142 -100
  59. package/dist/_chunks/Relations-CvifV6Y6.js.map +1 -0
  60. package/dist/_chunks/{en-C-V1_90f.js → en-BR48D_RH.js} +45 -18
  61. package/dist/_chunks/{en-C-V1_90f.js.map → en-BR48D_RH.js.map} +1 -1
  62. package/dist/_chunks/{en-MBPul9Su.mjs → en-D65uIF6Y.mjs} +45 -18
  63. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  64. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  65. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  66. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  67. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  68. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  69. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  70. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  71. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  72. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  73. package/dist/_chunks/{index-CAc9yTnx.mjs → index-BH2JnYpF.mjs} +2302 -995
  74. package/dist/_chunks/index-BH2JnYpF.mjs.map +1 -0
  75. package/dist/_chunks/{index-DNa1J4HE.js → index-DkJQjlak.js} +2273 -967
  76. package/dist/_chunks/index-DkJQjlak.js.map +1 -0
  77. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  78. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  79. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  80. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  81. package/dist/_chunks/{layout-BqtLA6Lb.js → layout-4BqLFW_b.js} +47 -32
  82. package/dist/_chunks/layout-4BqLFW_b.js.map +1 -0
  83. package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-bbOlPwLA.mjs} +46 -28
  84. package/dist/_chunks/layout-bbOlPwLA.mjs.map +1 -0
  85. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  86. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  87. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  88. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  89. package/dist/_chunks/{relations-mMFEcZRq.mjs → relations-HsflnFpO.mjs} +6 -7
  90. package/dist/_chunks/relations-HsflnFpO.mjs.map +1 -0
  91. package/dist/_chunks/{relations-BHY_KDJ_.js → relations-Yc0Z6A20.js} +6 -7
  92. package/dist/_chunks/relations-Yc0Z6A20.js.map +1 -0
  93. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  94. package/dist/_chunks/useDragAndDrop-BMtgCYzL.js.map +1 -0
  95. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  96. package/dist/_chunks/useDragAndDrop-DJ6jqvZN.mjs.map +1 -0
  97. package/dist/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
  98. package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
  99. package/dist/_chunks/usePrev-D5J_2fEu.js +28 -0
  100. package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
  101. package/dist/admin/index.js +4 -1
  102. package/dist/admin/index.js.map +1 -1
  103. package/dist/admin/index.mjs +10 -7
  104. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  105. package/dist/admin/src/content-manager.d.ts +7 -5
  106. package/dist/admin/src/exports.d.ts +3 -1
  107. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  108. package/dist/admin/src/history/index.d.ts +3 -0
  109. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  110. package/dist/admin/src/hooks/useDocument.d.ts +54 -9
  111. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  112. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  113. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  114. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  115. package/dist/admin/src/index.d.ts +1 -0
  116. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  117. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +12 -5
  118. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  119. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  120. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  121. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  122. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +5 -0
  123. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  124. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  125. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  126. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  127. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  128. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  129. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  130. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  131. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  132. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
  133. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  134. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  135. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  136. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  137. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  138. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  139. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  140. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  141. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  142. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  143. package/dist/admin/src/preview/index.d.ts +4 -0
  144. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  145. package/dist/admin/src/preview/routes.d.ts +3 -0
  146. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  147. package/dist/admin/src/router.d.ts +1 -1
  148. package/dist/admin/src/services/api.d.ts +2 -3
  149. package/dist/admin/src/services/components.d.ts +2 -2
  150. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  151. package/dist/admin/src/services/documents.d.ts +31 -20
  152. package/dist/admin/src/services/init.d.ts +2 -2
  153. package/dist/admin/src/services/relations.d.ts +3 -3
  154. package/dist/admin/src/services/uid.d.ts +3 -3
  155. package/dist/admin/src/utils/api.d.ts +4 -18
  156. package/dist/admin/src/utils/validation.d.ts +5 -7
  157. package/dist/server/index.js +959 -543
  158. package/dist/server/index.js.map +1 -1
  159. package/dist/server/index.mjs +960 -543
  160. package/dist/server/index.mjs.map +1 -1
  161. package/dist/server/src/bootstrap.d.ts.map +1 -1
  162. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  163. package/dist/server/src/controllers/index.d.ts.map +1 -1
  164. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  165. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  166. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  167. package/dist/server/src/controllers/utils/metadata.d.ts +23 -0
  168. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  169. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  170. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  171. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  172. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  173. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  174. package/dist/server/src/history/services/history.d.ts +3 -3
  175. package/dist/server/src/history/services/history.d.ts.map +1 -1
  176. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  177. package/dist/server/src/history/services/utils.d.ts +8 -12
  178. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  179. package/dist/server/src/index.d.ts +21 -36
  180. package/dist/server/src/index.d.ts.map +1 -1
  181. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  182. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  183. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  184. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  185. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  186. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  187. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  188. package/dist/server/src/preview/index.d.ts +4 -0
  189. package/dist/server/src/preview/index.d.ts.map +1 -0
  190. package/dist/server/src/preview/routes/index.d.ts +8 -0
  191. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  192. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  193. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  194. package/dist/server/src/preview/services/index.d.ts +16 -0
  195. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  196. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  197. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  198. package/dist/server/src/preview/services/preview.d.ts +12 -0
  199. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  200. package/dist/server/src/preview/utils.d.ts +19 -0
  201. package/dist/server/src/preview/utils.d.ts.map +1 -0
  202. package/dist/server/src/register.d.ts.map +1 -1
  203. package/dist/server/src/routes/index.d.ts.map +1 -1
  204. package/dist/server/src/services/document-manager.d.ts +11 -6
  205. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  206. package/dist/server/src/services/document-metadata.d.ts +16 -35
  207. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  208. package/dist/server/src/services/index.d.ts +21 -36
  209. package/dist/server/src/services/index.d.ts.map +1 -1
  210. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  211. package/dist/server/src/services/utils/populate.d.ts +8 -1
  212. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  213. package/dist/server/src/utils/index.d.ts +2 -0
  214. package/dist/server/src/utils/index.d.ts.map +1 -1
  215. package/dist/shared/contracts/collection-types.d.ts +17 -7
  216. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  217. package/dist/shared/contracts/index.d.ts +1 -0
  218. package/dist/shared/contracts/index.d.ts.map +1 -1
  219. package/dist/shared/contracts/preview.d.ts +27 -0
  220. package/dist/shared/contracts/preview.d.ts.map +1 -0
  221. package/dist/shared/contracts/relations.d.ts +2 -2
  222. package/dist/shared/contracts/relations.d.ts.map +1 -1
  223. package/dist/shared/index.js +4 -0
  224. package/dist/shared/index.js.map +1 -1
  225. package/dist/shared/index.mjs +4 -0
  226. package/dist/shared/index.mjs.map +1 -1
  227. package/package.json +22 -22
  228. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  229. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  230. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  231. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  232. package/dist/_chunks/EditViewPage-KRG56aCq.js +0 -224
  233. package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
  234. package/dist/_chunks/EditViewPage-aUnqL-63.mjs +0 -203
  235. package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
  236. package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
  237. package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
  238. package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
  239. package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
  240. package/dist/_chunks/History-BLEnudTX.js.map +0 -1
  241. package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
  242. package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
  243. package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
  244. package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
  245. package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
  246. package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
  247. package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
  248. package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
  249. package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
  250. package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
  251. package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
  252. package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
  253. package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
  254. package/dist/_chunks/relations-BHY_KDJ_.js.map +0 -1
  255. package/dist/_chunks/relations-mMFEcZRq.mjs.map +0 -1
  256. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  257. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  258. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  259. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  260. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +0 -1
  261. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +0 -1
  262. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  263. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
  264. 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
+ });
420
+ }
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
+ });
413
434
  }
414
- return currentDataWithRelations;
415
435
  },
416
- Promise.resolve(entry.data)
436
+ {
437
+ schema,
438
+ getModel: strapi2.getModel.bind(strapi2)
439
+ },
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
+ }
488
+ }
489
+ if (options.attribute.type === "dynamiczone") {
490
+ if (options.value === null) {
491
+ utils.set(options.key, []);
492
+ }
465
493
  }
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;
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);
470
502
  }
471
- if (attribute.type === "media") {
472
- const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
473
- previousRelationAttributes[name] = data2;
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,65 +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 !== "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 = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
579
+ if (!shouldCreateHistoryVersion(context)) {
580
+ return result;
581
+ }
582
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
519
583
  const defaultLocale = await serviceUtils.getDefaultLocale();
520
- const locale = documentContext.locale || defaultLocale;
521
- const document = await strapi2.documents(contentTypeUid).findOne({
522
- documentId: documentContext.documentId,
523
- locale,
524
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
584
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
585
+ if (!locales.length) {
586
+ return result;
587
+ }
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
+ )
525
603
  });
526
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
527
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
528
- const componentsSchemas = Object.keys(
529
- attributesSchema
530
- ).reduce((currentComponentSchemas, key) => {
531
- const fieldSchema = attributesSchema[key];
532
- if (fieldSchema.type === "component") {
533
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
534
- return {
535
- ...currentComponentSchemas,
536
- [fieldSchema.component]: componentSchema
537
- };
538
- }
539
- return currentComponentSchemas;
540
- }, {});
541
604
  await strapi2.db.transaction(async ({ onCommit }) => {
542
- onCommit(() => {
543
- historyService.createVersion({
544
- contentType: contentTypeUid,
545
- data: fp.omit(FIELDS_TO_IGNORE, document),
546
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
547
- componentsSchemas,
548
- relatedDocumentId: documentContext.documentId,
549
- locale,
550
- status
551
- });
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
+ }
552
617
  });
553
618
  });
554
619
  return result;
555
620
  });
556
- const retentionDays = serviceUtils.getRetentionDays();
557
- state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
558
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
621
+ state.deleteExpiredJob = nodeSchedule.scheduleJob("historyDaily", "0 0 * * *", () => {
622
+ const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
559
623
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
560
- query.deleteMany({
624
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
561
625
  where: {
562
626
  created_at: {
563
- $lt: expirationDate.toISOString()
627
+ $lt: expirationDate
564
628
  }
565
629
  }
630
+ }).catch((error) => {
631
+ if (error instanceof Error) {
632
+ strapi2.log.error("Error deleting expired history versions", error.message);
633
+ }
566
634
  });
567
635
  });
568
636
  state.isInitialized = true;
@@ -574,17 +642,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
574
642
  }
575
643
  };
576
644
  };
577
- const services$1 = {
645
+ const services$2 = {
578
646
  history: createHistoryService,
579
647
  lifecycles: createLifecyclesService
580
648
  };
581
- const info = { pluginName: "content-manager", type: "admin" };
649
+ const info$1 = { pluginName: "content-manager", type: "admin" };
582
650
  const historyVersionRouter = {
583
651
  type: "admin",
584
652
  routes: [
585
653
  {
586
654
  method: "GET",
587
- info,
655
+ info: info$1,
588
656
  path: "/history-versions",
589
657
  handler: "history-version.findMany",
590
658
  config: {
@@ -593,7 +661,7 @@ const historyVersionRouter = {
593
661
  },
594
662
  {
595
663
  method: "PUT",
596
- info,
664
+ info: info$1,
597
665
  path: "/history-versions/:versionId/restore",
598
666
  handler: "history-version.restoreVersion",
599
667
  config: {
@@ -602,7 +670,7 @@ const historyVersionRouter = {
602
670
  }
603
671
  ]
604
672
  };
605
- const routes$1 = {
673
+ const routes$2 = {
606
674
  "history-version": historyVersionRouter
607
675
  };
608
676
  const historyVersion = {
@@ -649,21 +717,21 @@ const historyVersion = {
649
717
  }
650
718
  }
651
719
  };
652
- const getFeature = () => {
720
+ const getFeature$1 = () => {
653
721
  if (strapi.ee.features.isEnabled("cms-content-history")) {
654
722
  return {
655
723
  register({ strapi: strapi2 }) {
656
724
  strapi2.get("models").add(historyVersion);
657
725
  },
658
726
  bootstrap({ strapi: strapi2 }) {
659
- getService(strapi2, "lifecycles").bootstrap();
727
+ getService$1(strapi2, "lifecycles").bootstrap();
660
728
  },
661
729
  destroy({ strapi: strapi2 }) {
662
- getService(strapi2, "lifecycles").destroy();
730
+ getService$1(strapi2, "lifecycles").destroy();
663
731
  },
664
- controllers: controllers$1,
665
- services: services$1,
666
- routes: routes$1
732
+ controllers: controllers$2,
733
+ services: services$2,
734
+ routes: routes$2
667
735
  };
668
736
  }
669
737
  return {
@@ -672,9 +740,201 @@ const getFeature = () => {
672
740
  }
673
741
  };
674
742
  };
675
- 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();
676
935
  const register = async ({ strapi: strapi2 }) => {
677
936
  await history.register?.({ strapi: strapi2 });
937
+ await preview.register?.({ strapi: strapi2 });
678
938
  };
679
939
  const ALLOWED_WEBHOOK_EVENTS = {
680
940
  ENTRY_PUBLISH: "entry.publish",
@@ -684,11 +944,12 @@ const bootstrap = async () => {
684
944
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
685
945
  strapi.get("webhookStore").addAllowedEvent(key, value);
686
946
  });
687
- getService$1("field-sizes").setCustomFieldInputSizes();
688
- await getService$1("components").syncConfigurations();
689
- await getService$1("content-types").syncConfigurations();
690
- 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();
691
951
  await history.bootstrap?.({ strapi });
952
+ await preview.bootstrap?.({ strapi });
692
953
  };
693
954
  const destroy = async ({ strapi: strapi2 }) => {
694
955
  await history.destroy?.({ strapi: strapi2 });
@@ -1178,7 +1439,8 @@ const admin = {
1178
1439
  };
1179
1440
  const routes = {
1180
1441
  admin,
1181
- ...history.routes ? history.routes : {}
1442
+ ...history.routes ? history.routes : {},
1443
+ ...preview.routes ? preview.routes : {}
1182
1444
  };
1183
1445
  const hasPermissionsSchema = strapiUtils.yup.object({
1184
1446
  actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
@@ -1189,6 +1451,11 @@ const { createPolicy } = strapiUtils.policy;
1189
1451
  const hasPermissions = createPolicy({
1190
1452
  name: "plugin::content-manager.hasPermissions",
1191
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
+ */
1192
1459
  handler(ctx, config = {}) {
1193
1460
  const { actions = [], hasAtLeastOne = false } = config;
1194
1461
  const { userAbility } = ctx.state;
@@ -1236,8 +1503,7 @@ const isSortable = (schema, name) => {
1236
1503
  if (!___default.default.has(schema.attributes, name)) {
1237
1504
  return false;
1238
1505
  }
1239
- if (schema.modelType === "component" && name === "id")
1240
- return false;
1506
+ if (schema.modelType === "component" && name === "id") return false;
1241
1507
  const attribute = schema.attributes[name];
1242
1508
  if (NON_SORTABLES.includes(attribute.type)) {
1243
1509
  return false;
@@ -1382,8 +1648,7 @@ const createDefaultSettings = async (schema) => {
1382
1648
  };
1383
1649
  };
1384
1650
  const syncSettings = async (configuration, schema) => {
1385
- if (fp.isEmpty(configuration.settings))
1386
- return createDefaultSettings(schema);
1651
+ if (fp.isEmpty(configuration.settings)) return createDefaultSettings(schema);
1387
1652
  const defaultField = getDefaultMainField(schema);
1388
1653
  const { mainField = defaultField, defaultSortBy = defaultField } = configuration.settings || {};
1389
1654
  return {
@@ -1430,7 +1695,7 @@ const createMetadasSchema = (schema) => {
1430
1695
  if (!value) {
1431
1696
  return strapiUtils.yup.string();
1432
1697
  }
1433
- const targetSchema = getService$1("content-types").findContentType(
1698
+ const targetSchema = getService$2("content-types").findContentType(
1434
1699
  schema.attributes[key].targetModel
1435
1700
  );
1436
1701
  if (!targetSchema) {
@@ -1478,7 +1743,7 @@ const { PaginationError, ValidationError } = strapiUtils.errors;
1478
1743
  const TYPES = ["singleType", "collectionType"];
1479
1744
  const kindSchema = strapiUtils.yup.string().oneOf(TYPES).nullable();
1480
1745
  const bulkActionInputSchema = strapiUtils.yup.object({
1481
- ids: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
1746
+ documentIds: strapiUtils.yup.array().of(strapiUtils.yup.strapiID()).min(1).required()
1482
1747
  }).required();
1483
1748
  const generateUIDInputSchema = strapiUtils.yup.object({
1484
1749
  contentTypeUID: strapiUtils.yup.string().required(),
@@ -1559,8 +1824,7 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1559
1824
  }
1560
1825
  switch (attribute.type) {
1561
1826
  case "relation": {
1562
- if (canCreate(attributePath))
1563
- return body2;
1827
+ if (canCreate(attributePath)) return body2;
1564
1828
  return fp.set(attributePath, { set: [] }, body2);
1565
1829
  }
1566
1830
  case "component": {
@@ -1570,29 +1834,62 @@ const excludeNotCreatableFields = (uid2, permissionChecker2) => (body, path = []
1570
1834
  ]);
1571
1835
  }
1572
1836
  default: {
1573
- if (canCreate(attributePath))
1574
- return body2;
1837
+ if (canCreate(attributePath)) return body2;
1575
1838
  return fp.set(attributePath, null, body2);
1576
1839
  }
1577
1840
  }
1578
1841
  }, body);
1579
1842
  };
1580
- const getDocumentLocaleAndStatus = (request) => {
1581
- const { locale, status, ...rest } = request || {};
1582
- if (!fp.isNil(locale) && typeof locale !== "string") {
1583
- throw new strapiUtils.errors.ValidationError(`Invalid locale: ${locale}`);
1584
- }
1585
- if (!fp.isNil(status) && !["draft", "published"].includes(status)) {
1586
- throw new strapiUtils.errors.ValidationError(`Invalid status: ${status}`);
1843
+ const singleLocaleSchema = strapiUtils.yup.string().nullable();
1844
+ const multipleLocaleSchema = strapiUtils.yup.lazy(
1845
+ (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1846
+ );
1847
+ const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1848
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1849
+ const { allowMultipleLocales } = opts;
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;
1853
+ const schema = strapiUtils.yup.object().shape({
1854
+ locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1855
+ status: statusSchema
1856
+ });
1857
+ try {
1858
+ await strapiUtils.validateYupSchema(schema, { strict: true, abortEarly: false })(request);
1859
+ return { locale, status, ...rest };
1860
+ } catch (error) {
1861
+ throw new strapiUtils.errors.ValidationError(`Validation error: ${error.message}`);
1587
1862
  }
1588
- return { locale, status, ...rest };
1863
+ };
1864
+ const formatDocumentWithMetadata = async (permissionChecker2, uid2, document, opts = {}) => {
1865
+ const documentMetadata2 = getService$2("document-metadata");
1866
+ const serviceOutput = await documentMetadata2.formatDocumentWithMetadata(uid2, document, opts);
1867
+ let {
1868
+ meta: { availableLocales, availableStatus }
1869
+ } = serviceOutput;
1870
+ const metadataSanitizer = permissionChecker2.sanitizeOutput;
1871
+ availableLocales = await strapiUtils.async.map(
1872
+ availableLocales,
1873
+ async (localeDocument) => metadataSanitizer(localeDocument)
1874
+ );
1875
+ availableStatus = await strapiUtils.async.map(
1876
+ availableStatus,
1877
+ async (statusDocument) => metadataSanitizer(statusDocument)
1878
+ );
1879
+ return {
1880
+ ...serviceOutput,
1881
+ meta: {
1882
+ availableLocales,
1883
+ availableStatus
1884
+ }
1885
+ };
1589
1886
  };
1590
1887
  const createDocument = async (ctx, opts) => {
1591
1888
  const { userAbility, user } = ctx.state;
1592
1889
  const { model } = ctx.params;
1593
1890
  const { body } = ctx.request;
1594
- const documentManager2 = getService$1("document-manager");
1595
- 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 });
1596
1893
  if (permissionChecker2.cannot.create()) {
1597
1894
  throw new strapiUtils.errors.ForbiddenError();
1598
1895
  }
@@ -1600,7 +1897,7 @@ const createDocument = async (ctx, opts) => {
1600
1897
  const setCreator = strapiUtils.setCreatorFields({ user });
1601
1898
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1602
1899
  const sanitizedBody = await sanitizeFn(body);
1603
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(body);
1900
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1604
1901
  return documentManager2.create(model, {
1605
1902
  data: sanitizedBody,
1606
1903
  locale,
@@ -1612,14 +1909,14 @@ const updateDocument = async (ctx, opts) => {
1612
1909
  const { userAbility, user } = ctx.state;
1613
1910
  const { id, model } = ctx.params;
1614
1911
  const { body } = ctx.request;
1615
- const documentManager2 = getService$1("document-manager");
1616
- 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 });
1617
1914
  if (permissionChecker2.cannot.update()) {
1618
1915
  throw new strapiUtils.errors.ForbiddenError();
1619
1916
  }
1620
1917
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1621
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1622
- const { locale } = getDocumentLocaleAndStatus(body);
1918
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
1919
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1623
1920
  const [documentVersion, documentExists] = await Promise.all([
1624
1921
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1625
1922
  documentManager2.exists(model, id)
@@ -1635,7 +1932,7 @@ const updateDocument = async (ctx, opts) => {
1635
1932
  throw new strapiUtils.errors.ForbiddenError();
1636
1933
  }
1637
1934
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1638
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1935
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1639
1936
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1640
1937
  const sanitizedBody = await sanitizeFn(body);
1641
1938
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1649,15 +1946,15 @@ const collectionTypes = {
1649
1946
  const { userAbility } = ctx.state;
1650
1947
  const { model } = ctx.params;
1651
1948
  const { query } = ctx.request;
1652
- const documentMetadata2 = getService$1("document-metadata");
1653
- const documentManager2 = getService$1("document-manager");
1654
- 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 });
1655
1952
  if (permissionChecker2.cannot.read()) {
1656
1953
  return ctx.forbidden();
1657
1954
  }
1658
1955
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1659
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1660
- const { locale, status } = 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);
1661
1958
  const { results: documents, pagination } = await documentManager2.findPage(
1662
1959
  { ...permissionQuery, populate, locale, status },
1663
1960
  model
@@ -1685,15 +1982,14 @@ const collectionTypes = {
1685
1982
  async findOne(ctx) {
1686
1983
  const { userAbility } = ctx.state;
1687
1984
  const { model, id } = ctx.params;
1688
- const documentManager2 = getService$1("document-manager");
1689
- const documentMetadata2 = getService$1("document-metadata");
1690
- 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 });
1691
1987
  if (permissionChecker2.cannot.read()) {
1692
1988
  return ctx.forbidden();
1693
1989
  }
1694
1990
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1695
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1696
- const { locale, status = "draft" } = 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);
1697
1993
  const version = await documentManager2.findOne(id, model, {
1698
1994
  populate,
1699
1995
  locale,
@@ -1704,9 +2000,11 @@ const collectionTypes = {
1704
2000
  if (!exists) {
1705
2001
  return ctx.notFound();
1706
2002
  }
1707
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2003
+ const { meta } = await formatDocumentWithMetadata(
2004
+ permissionChecker2,
1708
2005
  model,
1709
- { id, locale, publishedAt: null },
2006
+ // @ts-expect-error TODO: fix
2007
+ { documentId: id, locale, publishedAt: null },
1710
2008
  { availableLocales: true, availableStatus: false }
1711
2009
  );
1712
2010
  ctx.body = { data: {}, meta };
@@ -1716,20 +2014,19 @@ const collectionTypes = {
1716
2014
  return ctx.forbidden();
1717
2015
  }
1718
2016
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
1719
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2017
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1720
2018
  },
1721
2019
  async create(ctx) {
1722
2020
  const { userAbility } = ctx.state;
1723
2021
  const { model } = ctx.params;
1724
- const documentMetadata2 = getService$1("document-metadata");
1725
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2022
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1726
2023
  const [totalEntries, document] = await Promise.all([
1727
2024
  strapi.db.query(model).count(),
1728
2025
  createDocument(ctx)
1729
2026
  ]);
1730
2027
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
1731
2028
  ctx.status = 201;
1732
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
2029
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1733
2030
  // Empty metadata as it's not relevant for a new document
1734
2031
  availableLocales: false,
1735
2032
  availableStatus: false
@@ -1743,25 +2040,23 @@ const collectionTypes = {
1743
2040
  async update(ctx) {
1744
2041
  const { userAbility } = ctx.state;
1745
2042
  const { model } = ctx.params;
1746
- const documentMetadata2 = getService$1("document-metadata");
1747
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2043
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
1748
2044
  const updatedVersion = await updateDocument(ctx);
1749
2045
  const sanitizedVersion = await permissionChecker2.sanitizeOutput(updatedVersion);
1750
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedVersion);
2046
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedVersion);
1751
2047
  },
1752
2048
  async clone(ctx) {
1753
2049
  const { userAbility, user } = ctx.state;
1754
2050
  const { model, sourceId: id } = ctx.params;
1755
2051
  const { body } = ctx.request;
1756
- const documentManager2 = getService$1("document-manager");
1757
- const documentMetadata2 = getService$1("document-metadata");
1758
- 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 });
1759
2054
  if (permissionChecker2.cannot.create()) {
1760
2055
  return ctx.forbidden();
1761
2056
  }
1762
2057
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1763
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1764
- const { locale } = getDocumentLocaleAndStatus(body);
2058
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2059
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1765
2060
  const document = await documentManager2.findOne(id, model, {
1766
2061
  populate,
1767
2062
  locale,
@@ -1777,7 +2072,7 @@ const collectionTypes = {
1777
2072
  const sanitizedBody = await sanitizeFn(body);
1778
2073
  const clonedDocument = await documentManager2.clone(document.documentId, sanitizedBody, model);
1779
2074
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(clonedDocument);
1780
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument, {
2075
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument, {
1781
2076
  // Empty metadata as it's not relevant for a new document
1782
2077
  availableLocales: false,
1783
2078
  availableStatus: false
@@ -1799,14 +2094,14 @@ const collectionTypes = {
1799
2094
  async delete(ctx) {
1800
2095
  const { userAbility } = ctx.state;
1801
2096
  const { id, model } = ctx.params;
1802
- const documentManager2 = getService$1("document-manager");
1803
- 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 });
1804
2099
  if (permissionChecker2.cannot.delete()) {
1805
2100
  return ctx.forbidden();
1806
2101
  }
1807
2102
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1808
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1809
- const { locale } = getDocumentLocaleAndStatus(ctx.query);
2103
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2104
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1810
2105
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1811
2106
  if (documentLocales.length === 0) {
1812
2107
  return ctx.notFound();
@@ -1827,44 +2122,75 @@ const collectionTypes = {
1827
2122
  const { userAbility } = ctx.state;
1828
2123
  const { id, model } = ctx.params;
1829
2124
  const { body } = ctx.request;
1830
- const documentManager2 = getService$1("document-manager");
1831
- const documentMetadata2 = getService$1("document-metadata");
1832
- 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 });
1833
2127
  if (permissionChecker2.cannot.publish()) {
1834
2128
  return ctx.forbidden();
1835
2129
  }
1836
2130
  const publishedDocument = await strapi.db.transaction(async () => {
1837
2131
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1838
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1839
- 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
+ }
1840
2158
  if (permissionChecker2.cannot.publish(document)) {
1841
2159
  throw new strapiUtils.errors.ForbiddenError();
1842
2160
  }
1843
- const { locale } = getDocumentLocaleAndStatus(body);
1844
- return documentManager2.publish(document.documentId, model, {
2161
+ const publishResult = await documentManager2.publish(document.documentId, model, {
1845
2162
  locale
1846
2163
  // TODO: Allow setting creator fields on publish
1847
2164
  // data: setCreatorFields({ user, isEdition: true })({}),
1848
2165
  });
2166
+ if (!publishResult || publishResult.length === 0) {
2167
+ throw new strapiUtils.errors.NotFoundError("Document not found or already published.");
2168
+ }
2169
+ return publishResult[0];
1849
2170
  });
1850
2171
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
1851
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2172
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
1852
2173
  },
1853
2174
  async bulkPublish(ctx) {
1854
2175
  const { userAbility } = ctx.state;
1855
2176
  const { model } = ctx.params;
1856
2177
  const { body } = ctx.request;
1857
- const { ids } = body;
2178
+ const { documentIds } = body;
1858
2179
  await validateBulkActionInput(body);
1859
- const documentManager2 = getService$1("document-manager");
1860
- 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 });
1861
2182
  if (permissionChecker2.cannot.publish()) {
1862
2183
  return ctx.forbidden();
1863
2184
  }
1864
2185
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1865
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1866
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1867
- const entities = await Promise.all(entityPromises);
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
+ });
2190
+ const entityPromises = documentIds.map(
2191
+ (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
2192
+ );
2193
+ const entities = (await Promise.all(entityPromises)).flat();
1868
2194
  for (const entity of entities) {
1869
2195
  if (!entity) {
1870
2196
  return ctx.notFound();
@@ -1873,24 +2199,27 @@ const collectionTypes = {
1873
2199
  return ctx.forbidden();
1874
2200
  }
1875
2201
  }
1876
- const { count } = await documentManager2.publishMany(entities, model);
2202
+ const count = await documentManager2.publishMany(model, documentIds, locale);
1877
2203
  ctx.body = { count };
1878
2204
  },
1879
2205
  async bulkUnpublish(ctx) {
1880
2206
  const { userAbility } = ctx.state;
1881
2207
  const { model } = ctx.params;
1882
2208
  const { body } = ctx.request;
1883
- const { ids } = body;
2209
+ const { documentIds } = body;
1884
2210
  await validateBulkActionInput(body);
1885
- const documentManager2 = getService$1("document-manager");
1886
- 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 });
1887
2213
  if (permissionChecker2.cannot.unpublish()) {
1888
2214
  return ctx.forbidden();
1889
2215
  }
1890
- const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1891
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1892
- const entityPromises = ids.map((id) => documentManager2.findOne(id, model, { populate }));
1893
- const entities = await Promise.all(entityPromises);
2216
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2217
+ allowMultipleLocales: true
2218
+ });
2219
+ const entityPromises = documentIds.map(
2220
+ (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
2221
+ );
2222
+ const entities = (await Promise.all(entityPromises)).flat();
1894
2223
  for (const entity of entities) {
1895
2224
  if (!entity) {
1896
2225
  return ctx.notFound();
@@ -1899,7 +2228,8 @@ const collectionTypes = {
1899
2228
  return ctx.forbidden();
1900
2229
  }
1901
2230
  }
1902
- const { count } = await documentManager2.unpublishMany(entities, model);
2231
+ const entitiesIds = entities.map((document) => document.documentId);
2232
+ const { count } = await documentManager2.unpublishMany(entitiesIds, model, { locale });
1903
2233
  ctx.body = { count };
1904
2234
  },
1905
2235
  async unpublish(ctx) {
@@ -1908,9 +2238,8 @@ const collectionTypes = {
1908
2238
  const {
1909
2239
  body: { discardDraft, ...body }
1910
2240
  } = ctx.request;
1911
- const documentManager2 = getService$1("document-manager");
1912
- const documentMetadata2 = getService$1("document-metadata");
1913
- 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 });
1914
2243
  if (permissionChecker2.cannot.unpublish()) {
1915
2244
  return ctx.forbidden();
1916
2245
  }
@@ -1918,8 +2247,8 @@ const collectionTypes = {
1918
2247
  return ctx.forbidden();
1919
2248
  }
1920
2249
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1921
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1922
- const { locale } = getDocumentLocaleAndStatus(body);
2250
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2251
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1923
2252
  const document = await documentManager2.findOne(id, model, {
1924
2253
  populate,
1925
2254
  locale,
@@ -1941,7 +2270,7 @@ const collectionTypes = {
1941
2270
  ctx.body = await strapiUtils.async.pipe(
1942
2271
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
1943
2272
  permissionChecker2.sanitizeOutput,
1944
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2273
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1945
2274
  )(document);
1946
2275
  });
1947
2276
  },
@@ -1949,15 +2278,14 @@ const collectionTypes = {
1949
2278
  const { userAbility } = ctx.state;
1950
2279
  const { id, model } = ctx.params;
1951
2280
  const { body } = ctx.request;
1952
- const documentManager2 = getService$1("document-manager");
1953
- const documentMetadata2 = getService$1("document-metadata");
1954
- 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 });
1955
2283
  if (permissionChecker2.cannot.discard()) {
1956
2284
  return ctx.forbidden();
1957
2285
  }
1958
2286
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
1959
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1960
- const { locale } = getDocumentLocaleAndStatus(body);
2287
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2288
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1961
2289
  const document = await documentManager2.findOne(id, model, {
1962
2290
  populate,
1963
2291
  locale,
@@ -1972,42 +2300,50 @@ const collectionTypes = {
1972
2300
  ctx.body = await strapiUtils.async.pipe(
1973
2301
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
1974
2302
  permissionChecker2.sanitizeOutput,
1975
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
2303
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
1976
2304
  )(document);
1977
2305
  },
1978
2306
  async bulkDelete(ctx) {
1979
2307
  const { userAbility } = ctx.state;
1980
2308
  const { model } = ctx.params;
1981
2309
  const { query, body } = ctx.request;
1982
- const { ids } = body;
2310
+ const { documentIds } = body;
1983
2311
  await validateBulkActionInput(body);
1984
- const documentManager2 = getService$1("document-manager");
1985
- 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 });
1986
2314
  if (permissionChecker2.cannot.delete()) {
1987
2315
  return ctx.forbidden();
1988
2316
  }
1989
2317
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
1990
- const idsWhereClause = { id: { $in: ids } };
1991
- const params = {
1992
- ...permissionQuery,
1993
- filters: {
1994
- $and: [idsWhereClause].concat(permissionQuery.filters || [])
2318
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2319
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2320
+ const documentLocales = await documentManager2.findLocales(documentIds, model, {
2321
+ populate,
2322
+ locale
2323
+ });
2324
+ if (documentLocales.length === 0) {
2325
+ return ctx.notFound();
2326
+ }
2327
+ for (const document of documentLocales) {
2328
+ if (permissionChecker2.cannot.delete(document)) {
2329
+ return ctx.forbidden();
1995
2330
  }
1996
- };
1997
- const { count } = await documentManager2.deleteMany(params, model);
2331
+ }
2332
+ const localeDocumentsIds = documentLocales.map((document) => document.documentId);
2333
+ const { count } = await documentManager2.deleteMany(localeDocumentsIds, model, { locale });
1998
2334
  ctx.body = { count };
1999
2335
  },
2000
2336
  async countDraftRelations(ctx) {
2001
2337
  const { userAbility } = ctx.state;
2002
2338
  const { model, id } = ctx.params;
2003
- const documentManager2 = getService$1("document-manager");
2004
- 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 });
2005
2341
  if (permissionChecker2.cannot.read()) {
2006
2342
  return ctx.forbidden();
2007
2343
  }
2008
2344
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2009
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2010
- const { locale, status = "draft" } = getDocumentLocaleAndStatus(ctx.query);
2345
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2346
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2011
2347
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2012
2348
  if (!entity) {
2013
2349
  return ctx.notFound();
@@ -2022,24 +2358,24 @@ const collectionTypes = {
2022
2358
  },
2023
2359
  async countManyEntriesDraftRelations(ctx) {
2024
2360
  const { userAbility } = ctx.state;
2025
- const ids = ctx.request.query.ids;
2361
+ const ids = ctx.request.query.documentIds;
2026
2362
  const locale = ctx.request.query.locale;
2027
2363
  const { model } = ctx.params;
2028
- const documentManager2 = getService$1("document-manager");
2029
- 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 });
2030
2366
  if (permissionChecker2.cannot.read()) {
2031
2367
  return ctx.forbidden();
2032
2368
  }
2033
- const entities = await documentManager2.findMany(
2369
+ const documents = await documentManager2.findMany(
2034
2370
  {
2035
2371
  filters: {
2036
- id: ids
2372
+ documentId: ids
2037
2373
  },
2038
2374
  locale
2039
2375
  },
2040
2376
  model
2041
2377
  );
2042
- if (!entities) {
2378
+ if (!documents) {
2043
2379
  return ctx.notFound();
2044
2380
  }
2045
2381
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2050,13 +2386,13 @@ const collectionTypes = {
2050
2386
  };
2051
2387
  const components$1 = {
2052
2388
  findComponents(ctx) {
2053
- const components2 = getService$1("components").findAllComponents();
2054
- const { toDto } = getService$1("data-mapper");
2389
+ const components2 = getService$2("components").findAllComponents();
2390
+ const { toDto } = getService$2("data-mapper");
2055
2391
  ctx.body = { data: components2.map(toDto) };
2056
2392
  },
2057
2393
  async findComponentConfiguration(ctx) {
2058
2394
  const { uid: uid2 } = ctx.params;
2059
- const componentService = getService$1("components");
2395
+ const componentService = getService$2("components");
2060
2396
  const component = componentService.findComponent(uid2);
2061
2397
  if (!component) {
2062
2398
  return ctx.notFound("component.notFound");
@@ -2073,7 +2409,7 @@ const components$1 = {
2073
2409
  async updateComponentConfiguration(ctx) {
2074
2410
  const { uid: uid2 } = ctx.params;
2075
2411
  const { body } = ctx.request;
2076
- const componentService = getService$1("components");
2412
+ const componentService = getService$2("components");
2077
2413
  const component = componentService.findComponent(uid2);
2078
2414
  if (!component) {
2079
2415
  return ctx.notFound("component.notFound");
@@ -2107,12 +2443,12 @@ const contentTypes = {
2107
2443
  } catch (error) {
2108
2444
  return ctx.send({ error }, 400);
2109
2445
  }
2110
- const contentTypes2 = getService$1("content-types").findContentTypesByKind(kind);
2111
- const { toDto } = getService$1("data-mapper");
2446
+ const contentTypes2 = getService$2("content-types").findContentTypesByKind(kind);
2447
+ const { toDto } = getService$2("data-mapper");
2112
2448
  ctx.body = { data: contentTypes2.map(toDto) };
2113
2449
  },
2114
2450
  async findContentTypesSettings(ctx) {
2115
- const { findAllContentTypes, findConfiguration } = getService$1("content-types");
2451
+ const { findAllContentTypes, findConfiguration } = getService$2("content-types");
2116
2452
  const contentTypes2 = await findAllContentTypes();
2117
2453
  const configurations = await Promise.all(
2118
2454
  contentTypes2.map(async (contentType) => {
@@ -2126,7 +2462,7 @@ const contentTypes = {
2126
2462
  },
2127
2463
  async findContentTypeConfiguration(ctx) {
2128
2464
  const { uid: uid2 } = ctx.params;
2129
- const contentTypeService = getService$1("content-types");
2465
+ const contentTypeService = getService$2("content-types");
2130
2466
  const contentType = await contentTypeService.findContentType(uid2);
2131
2467
  if (!contentType) {
2132
2468
  return ctx.notFound("contentType.notFound");
@@ -2148,13 +2484,13 @@ const contentTypes = {
2148
2484
  const { userAbility } = ctx.state;
2149
2485
  const { uid: uid2 } = ctx.params;
2150
2486
  const { body } = ctx.request;
2151
- const contentTypeService = getService$1("content-types");
2152
- const metricsService = getService$1("metrics");
2487
+ const contentTypeService = getService$2("content-types");
2488
+ const metricsService = getService$2("metrics");
2153
2489
  const contentType = await contentTypeService.findContentType(uid2);
2154
2490
  if (!contentType) {
2155
2491
  return ctx.notFound("contentType.notFound");
2156
2492
  }
2157
- if (!getService$1("permission").canConfigureContentType({ userAbility, contentType })) {
2493
+ if (!getService$2("permission").canConfigureContentType({ userAbility, contentType })) {
2158
2494
  return ctx.forbidden();
2159
2495
  }
2160
2496
  let input;
@@ -2187,10 +2523,10 @@ const contentTypes = {
2187
2523
  };
2188
2524
  const init = {
2189
2525
  getInitData(ctx) {
2190
- const { toDto } = getService$1("data-mapper");
2191
- const { findAllComponents } = getService$1("components");
2192
- const { getAllFieldSizes } = getService$1("field-sizes");
2193
- 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");
2194
2530
  ctx.body = {
2195
2531
  data: {
2196
2532
  fieldSizes: getAllFieldSizes(),
@@ -2226,36 +2562,41 @@ const addFiltersClause = (params, filtersClause) => {
2226
2562
  params.filters.$and.push(filtersClause);
2227
2563
  };
2228
2564
  const sanitizeMainField = (model, mainField, userAbility) => {
2229
- const permissionChecker2 = getService$1("permission-checker").create({
2565
+ const permissionChecker2 = getService$2("permission-checker").create({
2230
2566
  userAbility,
2231
2567
  model: model.uid
2232
2568
  });
2233
- if (!isListable(model, mainField)) {
2569
+ const isMainFieldListable = isListable(model, mainField);
2570
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2571
+ if (!isMainFieldListable || !canReadMainField) {
2234
2572
  return "id";
2235
2573
  }
2236
- if (permissionChecker2.cannot.read(null, mainField)) {
2237
- if (model.uid === "plugin::users-permissions.role") {
2238
- const userPermissionChecker = getService$1("permission-checker").create({
2239
- userAbility,
2240
- model: "plugin::users-permissions.user"
2241
- });
2242
- if (userPermissionChecker.can.read()) {
2243
- return "name";
2244
- }
2245
- }
2246
- return "id";
2574
+ if (model.uid === "plugin::users-permissions.role") {
2575
+ return "name";
2247
2576
  }
2248
2577
  return mainField;
2249
2578
  };
2250
- const addStatusToRelations = async (uid2, relations2) => {
2251
- 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) {
2252
2585
  return relations2;
2253
2586
  }
2254
- const documentMetadata2 = getService$1("document-metadata");
2255
- 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
+ });
2256
2597
  return relations2.map((relation) => {
2257
- const availableStatuses = documentsAvailableStatus.filter(
2258
- (availableDocument) => availableDocument.documentId === relation.documentId
2598
+ const availableStatuses = availableStatus.filter(
2599
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2259
2600
  );
2260
2601
  return {
2261
2602
  ...relation,
@@ -2276,11 +2617,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2276
2617
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2277
2618
  const isSourceLocalized = isLocalized(sourceModel);
2278
2619
  const isTargetLocalized = isLocalized(targetModel);
2279
- let validatedLocale = locale;
2280
- if (!targetModel || !isTargetLocalized)
2281
- validatedLocale = void 0;
2282
2620
  return {
2283
- locale: validatedLocale,
2621
+ locale,
2284
2622
  isSourceLocalized,
2285
2623
  isTargetLocalized
2286
2624
  };
@@ -2289,8 +2627,7 @@ const validateStatus = (sourceUid, status) => {
2289
2627
  const sourceModel = strapi.getModel(sourceUid);
2290
2628
  const isDP = strapiUtils.contentTypes.hasDraftAndPublish;
2291
2629
  const isSourceDP = isDP(sourceModel);
2292
- if (!isSourceDP)
2293
- return { status: void 0 };
2630
+ if (!isSourceDP) return { status: void 0 };
2294
2631
  switch (status) {
2295
2632
  case "published":
2296
2633
  return { status: "published" };
@@ -2320,7 +2657,7 @@ const relations = {
2320
2657
  ctx.request?.query?.locale
2321
2658
  );
2322
2659
  const { status } = validateStatus(sourceUid, ctx.request?.query?.status);
2323
- const permissionChecker2 = getService$1("permission-checker").create({
2660
+ const permissionChecker2 = getService$2("permission-checker").create({
2324
2661
  userAbility,
2325
2662
  model
2326
2663
  });
@@ -2345,7 +2682,7 @@ const relations = {
2345
2682
  where.id = id;
2346
2683
  }
2347
2684
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2348
- const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2685
+ const populate = await getService$2("populate-builder")(model).populateFromQuery(permissionQuery).build();
2349
2686
  const currentEntity = await strapi.db.query(model).findOne({
2350
2687
  where,
2351
2688
  populate
@@ -2360,7 +2697,7 @@ const relations = {
2360
2697
  }
2361
2698
  entryId = currentEntity.id;
2362
2699
  }
2363
- 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);
2364
2701
  const targetSchema = strapi.getModel(targetUid);
2365
2702
  const mainField = fp.flow(
2366
2703
  fp.prop(`metadatas.${targetField}.edit.mainField`),
@@ -2383,7 +2720,7 @@ const relations = {
2383
2720
  attribute,
2384
2721
  fieldsToSelect,
2385
2722
  mainField,
2386
- source: { schema: sourceSchema },
2723
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2387
2724
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2388
2725
  sourceSchema,
2389
2726
  targetSchema,
@@ -2405,7 +2742,8 @@ const relations = {
2405
2742
  fieldsToSelect,
2406
2743
  mainField,
2407
2744
  source: {
2408
- schema: { uid: sourceUid, modelType: sourceModelType }
2745
+ schema: { uid: sourceUid, modelType: sourceModelType },
2746
+ isLocalized: isSourceLocalized
2409
2747
  },
2410
2748
  target: {
2411
2749
  schema: { uid: targetUid },
@@ -2413,7 +2751,7 @@ const relations = {
2413
2751
  }
2414
2752
  } = await this.extractAndValidateRequestInfo(ctx, id);
2415
2753
  const { idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
2416
- const permissionChecker2 = getService$1("permission-checker").create({
2754
+ const permissionChecker2 = getService$2("permission-checker").create({
2417
2755
  userAbility: ctx.state.userAbility,
2418
2756
  model: targetUid
2419
2757
  });
@@ -2443,12 +2781,16 @@ const relations = {
2443
2781
  } else {
2444
2782
  where.id = id;
2445
2783
  }
2446
- if (status) {
2447
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2784
+ const publishedAt = getPublishedAtClause(status, targetUid);
2785
+ if (!fp.isEmpty(publishedAt)) {
2786
+ where[`${alias}.published_at`] = publishedAt;
2448
2787
  }
2449
- if (filterByLocale) {
2788
+ if (isTargetLocalized && locale) {
2450
2789
  where[`${alias}.locale`] = locale;
2451
2790
  }
2791
+ if (isSourceLocalized && locale) {
2792
+ where.locale = locale;
2793
+ }
2452
2794
  if ((idsToInclude?.length ?? 0) !== 0) {
2453
2795
  where[`${alias}.id`].$notIn = idsToInclude;
2454
2796
  }
@@ -2466,7 +2808,8 @@ const relations = {
2466
2808
  id: { $notIn: fp.uniq(idsToOmit) }
2467
2809
  });
2468
2810
  }
2469
- 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);
2470
2813
  ctx.body = {
2471
2814
  ...res,
2472
2815
  results: await addStatusToRelations(targetUid, res.results)
@@ -2481,29 +2824,39 @@ const relations = {
2481
2824
  attribute,
2482
2825
  targetField,
2483
2826
  fieldsToSelect,
2484
- source: {
2485
- schema: { uid: sourceUid }
2486
- },
2487
- target: {
2488
- schema: { uid: targetUid }
2489
- }
2827
+ status,
2828
+ source: { schema: sourceSchema },
2829
+ target: { schema: targetSchema }
2490
2830
  } = await this.extractAndValidateRequestInfo(ctx, id);
2491
- 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 });
2492
2834
  const dbQuery = strapi.db.query(sourceUid);
2493
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
+ }
2494
2848
  const res = await loadRelations({ id: entryId }, targetField, {
2495
- select: ["id", "documentId", "locale", "publishedAt"],
2849
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2496
2850
  ordering: "desc",
2497
2851
  page: ctx.request.query.page,
2498
- pageSize: ctx.request.query.pageSize
2852
+ pageSize: ctx.request.query.pageSize,
2853
+ filters
2499
2854
  });
2500
2855
  const loadedIds = res.results.map((item) => item.id);
2501
2856
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2502
2857
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2503
2858
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2504
- ordering: "desc",
2505
- page: ctx.request.query.page,
2506
- pageSize: ctx.request.query.pageSize
2859
+ ordering: "desc"
2507
2860
  });
2508
2861
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2509
2862
  ctx.body = {
@@ -2518,10 +2871,10 @@ const relations = {
2518
2871
  }
2519
2872
  };
2520
2873
  const buildPopulateFromQuery = async (query, model) => {
2521
- 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();
2522
2875
  };
2523
2876
  const findDocument = async (query, uid2, opts = {}) => {
2524
- const documentManager2 = getService$1("document-manager");
2877
+ const documentManager2 = getService$2("document-manager");
2525
2878
  const populate = await buildPopulateFromQuery(query, uid2);
2526
2879
  return documentManager2.findMany({ ...opts, populate }, uid2).then((documents) => documents[0]);
2527
2880
  };
@@ -2529,13 +2882,13 @@ const createOrUpdateDocument = async (ctx, opts) => {
2529
2882
  const { user, userAbility } = ctx.state;
2530
2883
  const { model } = ctx.params;
2531
2884
  const { body, query } = ctx.request;
2532
- const documentManager2 = getService$1("document-manager");
2533
- 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 });
2534
2887
  if (permissionChecker2.cannot.create() && permissionChecker2.cannot.update()) {
2535
2888
  throw new strapiUtils.errors.ForbiddenError();
2536
2889
  }
2537
2890
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2538
- const { locale } = getDocumentLocaleAndStatus(body);
2891
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2539
2892
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2540
2893
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2541
2894
  // Find the first document to check if it exists
@@ -2571,13 +2924,12 @@ const singleTypes = {
2571
2924
  const { userAbility } = ctx.state;
2572
2925
  const { model } = ctx.params;
2573
2926
  const { query = {} } = ctx.request;
2574
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2575
- const documentMetadata2 = getService$1("document-metadata");
2927
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2576
2928
  if (permissionChecker2.cannot.read()) {
2577
2929
  return ctx.forbidden();
2578
2930
  }
2579
2931
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2580
- const { locale, status } = getDocumentLocaleAndStatus(query);
2932
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2581
2933
  const version = await findDocument(permissionQuery, model, { locale, status });
2582
2934
  if (!version) {
2583
2935
  if (permissionChecker2.cannot.create()) {
@@ -2587,9 +2939,11 @@ const singleTypes = {
2587
2939
  if (!document) {
2588
2940
  return ctx.notFound();
2589
2941
  }
2590
- const { meta } = await documentMetadata2.formatDocumentWithMetadata(
2942
+ const { meta } = await formatDocumentWithMetadata(
2943
+ permissionChecker2,
2591
2944
  model,
2592
- { id: document.documentId, locale, publishedAt: null },
2945
+ // @ts-expect-error - fix types
2946
+ { documentId: document.documentId, locale, publishedAt: null },
2593
2947
  { availableLocales: true, availableStatus: false }
2594
2948
  );
2595
2949
  ctx.body = { data: {}, meta };
@@ -2599,29 +2953,28 @@ const singleTypes = {
2599
2953
  return ctx.forbidden();
2600
2954
  }
2601
2955
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(version);
2602
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2956
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2603
2957
  },
2604
2958
  async createOrUpdate(ctx) {
2605
2959
  const { userAbility } = ctx.state;
2606
2960
  const { model } = ctx.params;
2607
- const documentMetadata2 = getService$1("document-metadata");
2608
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2961
+ const permissionChecker2 = getService$2("permission-checker").create({ userAbility, model });
2609
2962
  const document = await createOrUpdateDocument(ctx);
2610
2963
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(document);
2611
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
2964
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2612
2965
  },
2613
2966
  async delete(ctx) {
2614
2967
  const { userAbility } = ctx.state;
2615
2968
  const { model } = ctx.params;
2616
2969
  const { query = {} } = ctx.request;
2617
- const documentManager2 = getService$1("document-manager");
2618
- 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 });
2619
2972
  if (permissionChecker2.cannot.delete()) {
2620
2973
  return ctx.forbidden();
2621
2974
  }
2622
2975
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2623
2976
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2624
- const { locale } = getDocumentLocaleAndStatus(query);
2977
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2625
2978
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2626
2979
  populate,
2627
2980
  locale
@@ -2643,9 +2996,8 @@ const singleTypes = {
2643
2996
  const { userAbility } = ctx.state;
2644
2997
  const { model } = ctx.params;
2645
2998
  const { query = {} } = ctx.request;
2646
- const documentManager2 = getService$1("document-manager");
2647
- const documentMetadata2 = getService$1("document-metadata");
2648
- 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 });
2649
3001
  if (permissionChecker2.cannot.publish()) {
2650
3002
  return ctx.forbidden();
2651
3003
  }
@@ -2659,11 +3011,12 @@ const singleTypes = {
2659
3011
  if (permissionChecker2.cannot.publish(document)) {
2660
3012
  throw new strapiUtils.errors.ForbiddenError();
2661
3013
  }
2662
- const { locale } = getDocumentLocaleAndStatus(document);
2663
- return documentManager2.publish(document.documentId, model, { locale });
3014
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
3015
+ const publishResult = await documentManager2.publish(document.documentId, model, { locale });
3016
+ return publishResult.at(0);
2664
3017
  });
2665
3018
  const sanitizedDocument = await permissionChecker2.sanitizeOutput(publishedDocument);
2666
- ctx.body = await documentMetadata2.formatDocumentWithMetadata(model, sanitizedDocument);
3019
+ ctx.body = await formatDocumentWithMetadata(permissionChecker2, model, sanitizedDocument);
2667
3020
  },
2668
3021
  async unpublish(ctx) {
2669
3022
  const { userAbility } = ctx.state;
@@ -2672,9 +3025,8 @@ const singleTypes = {
2672
3025
  body: { discardDraft, ...body },
2673
3026
  query = {}
2674
3027
  } = ctx.request;
2675
- const documentManager2 = getService$1("document-manager");
2676
- const documentMetadata2 = getService$1("document-metadata");
2677
- 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 });
2678
3030
  if (permissionChecker2.cannot.unpublish()) {
2679
3031
  return ctx.forbidden();
2680
3032
  }
@@ -2682,7 +3034,7 @@ const singleTypes = {
2682
3034
  return ctx.forbidden();
2683
3035
  }
2684
3036
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2685
- const { locale } = getDocumentLocaleAndStatus(body);
3037
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2686
3038
  const document = await findDocument(sanitizedQuery, model, { locale });
2687
3039
  if (!document) {
2688
3040
  return ctx.notFound();
@@ -2700,7 +3052,7 @@ const singleTypes = {
2700
3052
  ctx.body = await strapiUtils.async.pipe(
2701
3053
  (document2) => documentManager2.unpublish(document2.documentId, model, { locale }),
2702
3054
  permissionChecker2.sanitizeOutput,
2703
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
3055
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2704
3056
  )(document);
2705
3057
  });
2706
3058
  },
@@ -2708,14 +3060,13 @@ const singleTypes = {
2708
3060
  const { userAbility } = ctx.state;
2709
3061
  const { model } = ctx.params;
2710
3062
  const { body, query = {} } = ctx.request;
2711
- const documentManager2 = getService$1("document-manager");
2712
- const documentMetadata2 = getService$1("document-metadata");
2713
- 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 });
2714
3065
  if (permissionChecker2.cannot.discard()) {
2715
3066
  return ctx.forbidden();
2716
3067
  }
2717
3068
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2718
- const { locale } = getDocumentLocaleAndStatus(body);
3069
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2719
3070
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2720
3071
  if (!document) {
2721
3072
  return ctx.notFound();
@@ -2726,16 +3077,16 @@ const singleTypes = {
2726
3077
  ctx.body = await strapiUtils.async.pipe(
2727
3078
  (document2) => documentManager2.discardDraft(document2.documentId, model, { locale }),
2728
3079
  permissionChecker2.sanitizeOutput,
2729
- (document2) => documentMetadata2.formatDocumentWithMetadata(model, document2)
3080
+ (document2) => formatDocumentWithMetadata(permissionChecker2, model, document2)
2730
3081
  )(document);
2731
3082
  },
2732
3083
  async countDraftRelations(ctx) {
2733
3084
  const { userAbility } = ctx.state;
2734
3085
  const { model } = ctx.params;
2735
3086
  const { query } = ctx.request;
2736
- const documentManager2 = getService$1("document-manager");
2737
- const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2738
- const { locale } = 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);
2739
3090
  if (permissionChecker2.cannot.read()) {
2740
3091
  return ctx.forbidden();
2741
3092
  }
@@ -2756,9 +3107,9 @@ const uid$1 = {
2756
3107
  async generateUID(ctx) {
2757
3108
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2758
3109
  const { query = {} } = ctx.request;
2759
- const { locale } = getDocumentLocaleAndStatus(query);
3110
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2760
3111
  await validateUIDField(contentTypeUID, field);
2761
- const uidService = getService$1("uid");
3112
+ const uidService = getService$2("uid");
2762
3113
  ctx.body = {
2763
3114
  data: await uidService.generateUIDField({ contentTypeUID, field, data, locale })
2764
3115
  };
@@ -2768,9 +3119,9 @@ const uid$1 = {
2768
3119
  ctx.request.body
2769
3120
  );
2770
3121
  const { query = {} } = ctx.request;
2771
- const { locale } = getDocumentLocaleAndStatus(query);
3122
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2772
3123
  await validateUIDField(contentTypeUID, field);
2773
- const uidService = getService$1("uid");
3124
+ const uidService = getService$2("uid");
2774
3125
  const isAvailable = await uidService.checkUIDAvailability({
2775
3126
  contentTypeUID,
2776
3127
  field,
@@ -2791,7 +3142,8 @@ const controllers = {
2791
3142
  relations,
2792
3143
  "single-types": singleTypes,
2793
3144
  uid: uid$1,
2794
- ...history.controllers ? history.controllers : {}
3145
+ ...history.controllers ? history.controllers : {},
3146
+ ...preview.controllers ? preview.controllers : {}
2795
3147
  };
2796
3148
  const keys = {
2797
3149
  CONFIGURATION: "configuration"
@@ -2920,18 +3272,15 @@ async function syncMetadatas(configuration, schema) {
2920
3272
  ___default.default.set(updatedMeta, ["list", "searchable"], false);
2921
3273
  ___default.default.set(acc, [key], updatedMeta);
2922
3274
  }
2923
- if (!___default.default.has(edit, "mainField"))
2924
- return acc;
3275
+ if (!___default.default.has(edit, "mainField")) return acc;
2925
3276
  if (!isRelation$1(attr)) {
2926
3277
  ___default.default.set(updatedMeta, "edit", ___default.default.omit(edit, ["mainField"]));
2927
3278
  ___default.default.set(acc, [key], updatedMeta);
2928
3279
  return acc;
2929
3280
  }
2930
- if (edit.mainField === "id")
2931
- return acc;
3281
+ if (edit.mainField === "id") return acc;
2932
3282
  const targetSchema = getTargetSchema(attr.targetModel);
2933
- if (!targetSchema)
2934
- return acc;
3283
+ if (!targetSchema) return acc;
2935
3284
  if (!isSortable(targetSchema, edit.mainField) && !isListable(targetSchema, edit.mainField)) {
2936
3285
  ___default.default.set(updatedMeta, ["edit", "mainField"], getDefaultMainField(targetSchema));
2937
3286
  ___default.default.set(acc, [key], updatedMeta);
@@ -2942,12 +3291,12 @@ async function syncMetadatas(configuration, schema) {
2942
3291
  return ___default.default.assign(metasWithDefaults, updatedMetas);
2943
3292
  }
2944
3293
  const getTargetSchema = (targetModel) => {
2945
- return getService$1("content-types").findContentType(targetModel);
3294
+ return getService$2("content-types").findContentType(targetModel);
2946
3295
  };
2947
3296
  const DEFAULT_LIST_LENGTH = 4;
2948
3297
  const MAX_ROW_SIZE = 12;
2949
3298
  const isAllowedFieldSize = (type, size) => {
2950
- const { getFieldSize } = getService$1("field-sizes");
3299
+ const { getFieldSize } = getService$2("field-sizes");
2951
3300
  const fieldSize = getFieldSize(type);
2952
3301
  if (!fieldSize.isResizable && size !== fieldSize.default) {
2953
3302
  return false;
@@ -2955,7 +3304,7 @@ const isAllowedFieldSize = (type, size) => {
2955
3304
  return size <= MAX_ROW_SIZE;
2956
3305
  };
2957
3306
  const getDefaultFieldSize = (attribute) => {
2958
- const { hasFieldSize, getFieldSize } = getService$1("field-sizes");
3307
+ const { hasFieldSize, getFieldSize } = getService$2("field-sizes");
2959
3308
  return getFieldSize(hasFieldSize(attribute.customField) ? attribute.customField : attribute.type).default;
2960
3309
  };
2961
3310
  async function createDefaultLayouts(schema) {
@@ -2976,8 +3325,7 @@ function createDefaultEditLayout(schema) {
2976
3325
  return appendToEditLayout([], keys2, schema);
2977
3326
  }
2978
3327
  function syncLayouts(configuration, schema) {
2979
- if (___default.default.isEmpty(configuration.layouts))
2980
- return createDefaultLayouts(schema);
3328
+ if (___default.default.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
2981
3329
  const { list = [], editRelations = [], edit = [] } = configuration.layouts || {};
2982
3330
  let cleanList = list.filter((attr) => isListable(schema, attr));
2983
3331
  const cleanEditRelations = editRelations.filter(
@@ -2988,9 +3336,8 @@ function syncLayouts(configuration, schema) {
2988
3336
  for (const row of edit) {
2989
3337
  const newRow = [];
2990
3338
  for (const el of row) {
2991
- if (!hasEditableAttribute(schema, el.name))
2992
- continue;
2993
- const { hasFieldSize } = getService$1("field-sizes");
3339
+ if (!hasEditableAttribute(schema, el.name)) continue;
3340
+ const { hasFieldSize } = getService$2("field-sizes");
2994
3341
  const fieldType = hasFieldSize(schema.attributes[el.name].customField) ? schema.attributes[el.name].customField : schema.attributes[el.name].type;
2995
3342
  if (!isAllowedFieldSize(fieldType, el.size)) {
2996
3343
  elementsToReAppend.push(el.name);
@@ -3020,8 +3367,7 @@ function syncLayouts(configuration, schema) {
3020
3367
  };
3021
3368
  }
3022
3369
  const appendToEditLayout = (layout = [], keysToAppend, schema) => {
3023
- if (keysToAppend.length === 0)
3024
- return layout;
3370
+ if (keysToAppend.length === 0) return layout;
3025
3371
  let currentRowIndex = Math.max(layout.length - 1, 0);
3026
3372
  if (!layout[currentRowIndex]) {
3027
3373
  layout[currentRowIndex] = [];
@@ -3130,17 +3476,17 @@ const configurationService$1 = createConfigurationService({
3130
3476
  isComponent: true,
3131
3477
  prefix: STORE_KEY_PREFIX,
3132
3478
  getModels() {
3133
- const { toContentManagerModel } = getService$1("data-mapper");
3479
+ const { toContentManagerModel } = getService$2("data-mapper");
3134
3480
  return fp.mapValues(toContentManagerModel, strapi.components);
3135
3481
  }
3136
3482
  });
3137
3483
  const components = ({ strapi: strapi2 }) => ({
3138
3484
  findAllComponents() {
3139
- const { toContentManagerModel } = getService$1("data-mapper");
3485
+ const { toContentManagerModel } = getService$2("data-mapper");
3140
3486
  return Object.values(strapi2.components).map(toContentManagerModel);
3141
3487
  },
3142
3488
  findComponent(uid2) {
3143
- const { toContentManagerModel } = getService$1("data-mapper");
3489
+ const { toContentManagerModel } = getService$2("data-mapper");
3144
3490
  const component = strapi2.components[uid2];
3145
3491
  return fp.isNil(component) ? component : toContentManagerModel(component);
3146
3492
  },
@@ -3191,17 +3537,17 @@ const configurationService = createConfigurationService({
3191
3537
  storeUtils,
3192
3538
  prefix: "content_types",
3193
3539
  getModels() {
3194
- const { toContentManagerModel } = getService$1("data-mapper");
3540
+ const { toContentManagerModel } = getService$2("data-mapper");
3195
3541
  return fp.mapValues(toContentManagerModel, strapi.contentTypes);
3196
3542
  }
3197
3543
  });
3198
3544
  const service = ({ strapi: strapi2 }) => ({
3199
3545
  findAllContentTypes() {
3200
- const { toContentManagerModel } = getService$1("data-mapper");
3546
+ const { toContentManagerModel } = getService$2("data-mapper");
3201
3547
  return Object.values(strapi2.contentTypes).map(toContentManagerModel);
3202
3548
  },
3203
3549
  findContentType(uid2) {
3204
- const { toContentManagerModel } = getService$1("data-mapper");
3550
+ const { toContentManagerModel } = getService$2("data-mapper");
3205
3551
  const contentType = strapi2.contentTypes[uid2];
3206
3552
  return fp.isNil(contentType) ? contentType : toContentManagerModel(contentType);
3207
3553
  },
@@ -3230,7 +3576,7 @@ const service = ({ strapi: strapi2 }) => ({
3230
3576
  return this.findConfiguration(contentType);
3231
3577
  },
3232
3578
  findComponentsConfigurations(contentType) {
3233
- return getService$1("components").findComponentsConfigurations(contentType);
3579
+ return getService$2("components").findComponentsConfigurations(contentType);
3234
3580
  },
3235
3581
  syncConfigurations() {
3236
3582
  return configurationService.syncConfigurations();
@@ -3411,12 +3757,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3411
3757
  ability: userAbility,
3412
3758
  model
3413
3759
  });
3414
- 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
+ };
3415
3764
  const can = (action, entity, field) => {
3416
- 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
+ );
3417
3772
  };
3418
3773
  const cannot = (action, entity, field) => {
3419
- 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
+ );
3420
3781
  };
3421
3782
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3422
3783
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3487,7 +3848,7 @@ const permission = ({ strapi: strapi2 }) => ({
3487
3848
  return userAbility.can(action);
3488
3849
  },
3489
3850
  async registerPermissions() {
3490
- const displayedContentTypes = getService$1("content-types").findDisplayedContentTypes();
3851
+ const displayedContentTypes = getService$2("content-types").findDisplayedContentTypes();
3491
3852
  const contentTypesUids = displayedContentTypes.map(fp.prop("uid"));
3492
3853
  const actions = [
3493
3854
  {
@@ -3559,7 +3920,7 @@ const permission = ({ strapi: strapi2 }) => ({
3559
3920
  await strapi2.service("admin::permission").actionProvider.registerMany(actions);
3560
3921
  }
3561
3922
  });
3562
- const { isVisibleAttribute: isVisibleAttribute$1 } = strapiUtils__default.default.contentTypes;
3923
+ const { isVisibleAttribute: isVisibleAttribute$1, isScalarAttribute, getDoesAttributeRequireValidation } = strapiUtils__default.default.contentTypes;
3563
3924
  const { isAnyToMany } = strapiUtils__default.default.relations;
3564
3925
  const { PUBLISHED_AT_ATTRIBUTE: PUBLISHED_AT_ATTRIBUTE$1 } = strapiUtils__default.default.contentTypes.constants;
3565
3926
  const isMorphToRelation = (attribute) => isRelation(attribute) && attribute.relation.includes("morphTo");
@@ -3572,6 +3933,12 @@ function getPopulateForRelation(attribute, model, attributeName, { countMany, co
3572
3933
  if (initialPopulate) {
3573
3934
  return initialPopulate;
3574
3935
  }
3936
+ if (attributeName === "localizations") {
3937
+ const validationPopulate = getPopulateForValidation(model.uid);
3938
+ return {
3939
+ populate: validationPopulate.populate
3940
+ };
3941
+ }
3575
3942
  if (!isVisibleAttribute$1(model, attributeName)) {
3576
3943
  return true;
3577
3944
  }
@@ -3631,6 +3998,9 @@ const getDeepPopulate = (uid2, {
3631
3998
  return {};
3632
3999
  }
3633
4000
  const model = strapi.getModel(uid2);
4001
+ if (!model) {
4002
+ return {};
4003
+ }
3634
4004
  return Object.keys(model.attributes).reduce(
3635
4005
  (populateAcc, attributeName) => fp.merge(
3636
4006
  populateAcc,
@@ -3650,6 +4020,48 @@ const getDeepPopulate = (uid2, {
3650
4020
  {}
3651
4021
  );
3652
4022
  };
4023
+ const getPopulateForValidation = (uid2) => {
4024
+ const model = strapi.getModel(uid2);
4025
+ if (!model) {
4026
+ return {};
4027
+ }
4028
+ return Object.entries(model.attributes).reduce((populateAcc, [attributeName, attribute]) => {
4029
+ if (isScalarAttribute(attribute)) {
4030
+ if (getDoesAttributeRequireValidation(attribute)) {
4031
+ populateAcc.fields = populateAcc.fields || [];
4032
+ populateAcc.fields.push(attributeName);
4033
+ }
4034
+ return populateAcc;
4035
+ }
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;
4044
+ }
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;
4054
+ },
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;
4063
+ }, {});
4064
+ };
3653
4065
  const getDeepPopulateDraftCount = (uid2) => {
3654
4066
  const model = strapi.getModel(uid2);
3655
4067
  let hasRelations = false;
@@ -3657,6 +4069,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3657
4069
  const attribute = model.attributes[attributeName];
3658
4070
  switch (attribute.type) {
3659
4071
  case "relation": {
4072
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
4073
+ if (isMorphRelation) {
4074
+ break;
4075
+ }
3660
4076
  if (isVisibleAttribute$1(model, attributeName)) {
3661
4077
  populateAcc[attributeName] = {
3662
4078
  count: true,
@@ -3671,22 +4087,24 @@ const getDeepPopulateDraftCount = (uid2) => {
3671
4087
  attribute.component
3672
4088
  );
3673
4089
  if (childHasRelations) {
3674
- populateAcc[attributeName] = { populate: populate2 };
4090
+ populateAcc[attributeName] = {
4091
+ populate: populate2
4092
+ };
3675
4093
  hasRelations = true;
3676
4094
  }
3677
4095
  break;
3678
4096
  }
3679
4097
  case "dynamiczone": {
3680
- const dzPopulate = (attribute.components || []).reduce((acc, componentUID) => {
3681
- const { populate: populate2, hasRelations: childHasRelations } = getDeepPopulateDraftCount(componentUID);
3682
- if (childHasRelations) {
4098
+ const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
4099
+ const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
4100
+ if (componentHasRelations) {
3683
4101
  hasRelations = true;
3684
- return fp.merge(acc, populate2);
4102
+ return { ...acc, [componentUID]: { populate: componentPopulate } };
3685
4103
  }
3686
4104
  return acc;
3687
4105
  }, {});
3688
- if (!fp.isEmpty(dzPopulate)) {
3689
- populateAcc[attributeName] = { populate: dzPopulate };
4106
+ if (!fp.isEmpty(dzPopulateFragment)) {
4107
+ populateAcc[attributeName] = { on: dzPopulateFragment };
3690
4108
  }
3691
4109
  break;
3692
4110
  }
@@ -3721,7 +4139,7 @@ const getQueryPopulate = async (uid2, query) => {
3721
4139
  return populateQuery;
3722
4140
  };
3723
4141
  const buildDeepPopulate = (uid2) => {
3724
- return getService$1("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
4142
+ return getService$2("populate-builder")(uid2).populateDeep(Infinity).countRelations().build();
3725
4143
  };
3726
4144
  const populateBuilder = (uid2) => {
3727
4145
  let getInitialPopulate = async () => {
@@ -3878,41 +4296,55 @@ const AVAILABLE_STATUS_FIELDS = [
3878
4296
  "updatedBy",
3879
4297
  "status"
3880
4298
  ];
3881
- const AVAILABLE_LOCALES_FIELDS = ["id", "locale", "updatedAt", "createdAt", "status"];
4299
+ const AVAILABLE_LOCALES_FIELDS = [
4300
+ "id",
4301
+ "locale",
4302
+ "updatedAt",
4303
+ "createdAt",
4304
+ "publishedAt",
4305
+ "documentId"
4306
+ ];
3882
4307
  const CONTENT_MANAGER_STATUS = {
3883
4308
  PUBLISHED: "published",
3884
4309
  DRAFT: "draft",
3885
4310
  MODIFIED: "modified"
3886
4311
  };
3887
- const areDatesEqual = (date1, date2, threshold) => {
3888
- if (!date1 || !date2) {
4312
+ const getIsVersionLatestModification = (version, otherVersion) => {
4313
+ if (!version || !version.updatedAt) {
3889
4314
  return false;
3890
4315
  }
3891
- const time1 = new Date(date1).getTime();
3892
- const time2 = new Date(date2).getTime();
3893
- const difference = Math.abs(time1 - time2);
3894
- return difference <= threshold;
4316
+ const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;
4317
+ const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;
4318
+ return versionUpdatedAt > otherUpdatedAt;
3895
4319
  };
3896
4320
  const documentMetadata = ({ strapi: strapi2 }) => ({
3897
4321
  /**
3898
4322
  * Returns available locales of a document for the current status
3899
4323
  */
3900
- getAvailableLocales(uid2, version, allVersions) {
4324
+ async getAvailableLocales(uid2, version, allVersions) {
3901
4325
  const versionsByLocale = fp.groupBy("locale", allVersions);
3902
- delete versionsByLocale[version.locale];
3903
- return Object.values(versionsByLocale).map((localeVersions) => {
3904
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2))) {
3905
- return fp.pick(AVAILABLE_LOCALES_FIELDS, localeVersions[0]);
3906
- }
3907
- const draftVersion = localeVersions.find((v) => v.publishedAt === null);
3908
- const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
3909
- if (!draftVersion)
3910
- return;
3911
- return {
3912
- ...fp.pick(AVAILABLE_LOCALES_FIELDS, draftVersion),
3913
- status: this.getStatus(draftVersion, otherVersions)
3914
- };
3915
- }).filter(Boolean);
4326
+ if (version.locale) {
4327
+ delete versionsByLocale[version.locale];
4328
+ }
4329
+ const model = strapi2.getModel(uid2);
4330
+ const mappingResult = await strapiUtils.async.map(
4331
+ Object.values(versionsByLocale),
4332
+ async (localeVersions) => {
4333
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(model)) {
4334
+ return localeVersions[0];
4335
+ }
4336
+ const draftVersion = localeVersions.find((v) => v.publishedAt === null);
4337
+ const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);
4338
+ if (!draftVersion) {
4339
+ return;
4340
+ }
4341
+ return {
4342
+ ...draftVersion,
4343
+ status: this.getStatus(draftVersion, otherVersions)
4344
+ };
4345
+ }
4346
+ );
4347
+ return mappingResult.filter(Boolean);
3916
4348
  },
3917
4349
  /**
3918
4350
  * Returns available status of a document for the current locale
@@ -3924,8 +4356,7 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3924
4356
  const matchStatus = status === "published" ? v.publishedAt !== null : v.publishedAt === null;
3925
4357
  return matchLocale && matchStatus;
3926
4358
  });
3927
- if (!availableStatus)
3928
- return availableStatus;
4359
+ if (!availableStatus) return availableStatus;
3929
4360
  return fp.pick(AVAILABLE_STATUS_FIELDS, availableStatus);
3930
4361
  },
3931
4362
  /**
@@ -3935,50 +4366,64 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3935
4366
  * @returns
3936
4367
  */
3937
4368
  async getManyAvailableStatus(uid2, documents) {
3938
- if (!documents.length)
3939
- return [];
4369
+ if (!documents.length) return [];
3940
4370
  const status = documents[0].publishedAt !== null ? "published" : "draft";
3941
- const locale = documents[0]?.locale;
3942
- const otherStatus = status === "published" ? "draft" : "published";
3943
- return strapi2.documents(uid2).findMany({
3944
- filters: {
3945
- documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) }
3946
- },
3947
- status: otherStatus,
3948
- locale,
3949
- 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"]
3950
4382
  });
3951
4383
  },
3952
4384
  getStatus(version, otherDocumentStatuses) {
3953
- const isDraft = version.publishedAt === null;
3954
- if (!otherDocumentStatuses?.length) {
3955
- return isDraft ? CONTENT_MANAGER_STATUS.DRAFT : CONTENT_MANAGER_STATUS.PUBLISHED;
3956
- }
3957
- if (isDraft) {
3958
- const publishedVersion = otherDocumentStatuses?.find((d) => d.publishedAt !== null);
3959
- if (!publishedVersion) {
3960
- return CONTENT_MANAGER_STATUS.DRAFT;
3961
- }
4385
+ let draftVersion;
4386
+ let publishedVersion;
4387
+ if (version.publishedAt) {
4388
+ publishedVersion = version;
4389
+ } else {
4390
+ draftVersion = version;
3962
4391
  }
3963
- if (areDatesEqual(version.updatedAt, otherDocumentStatuses.at(0)?.updatedAt, 500)) {
3964
- return CONTENT_MANAGER_STATUS.PUBLISHED;
4392
+ const otherVersion = otherDocumentStatuses?.at(0);
4393
+ if (otherVersion?.publishedAt) {
4394
+ publishedVersion = otherVersion;
4395
+ } else if (otherVersion) {
4396
+ draftVersion = otherVersion;
3965
4397
  }
3966
- return CONTENT_MANAGER_STATUS.MODIFIED;
4398
+ if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;
4399
+ if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;
4400
+ const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);
4401
+ return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;
3967
4402
  },
4403
+ // TODO is it necessary to return metadata on every page of the CM
4404
+ // We could refactor this so the locales are only loaded when they're
4405
+ // needed. e.g. in the bulk locale action modal.
3968
4406
  async getMetadata(uid2, version, { availableLocales = true, availableStatus = true } = {}) {
3969
- const versions = await strapi2.db.query(uid2).findMany({
3970
- where: { documentId: version.documentId },
3971
- select: ["createdAt", "updatedAt", "locale", "publishedAt", "documentId"],
4407
+ const { populate = {}, fields = [] } = getPopulateForValidation(uid2);
4408
+ const params = {
3972
4409
  populate: {
4410
+ ...populate,
4411
+ // NOTE: creator fields are selected in this way to avoid exposing sensitive data
3973
4412
  createdBy: {
3974
4413
  select: ["id", "firstname", "lastname", "email"]
3975
4414
  },
3976
4415
  updatedBy: {
3977
4416
  select: ["id", "firstname", "lastname", "email"]
3978
4417
  }
4418
+ },
4419
+ fields: fp.uniq([...AVAILABLE_LOCALES_FIELDS, ...fields]),
4420
+ filters: {
4421
+ documentId: version.documentId
3979
4422
  }
3980
- });
3981
- const availableLocalesResult = availableLocales ? this.getAvailableLocales(uid2, version, versions) : [];
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) : [];
3982
4427
  const availableStatusResult = availableStatus ? this.getAvailableStatus(version, versions) : null;
3983
4428
  return {
3984
4429
  availableLocales: availableLocalesResult,
@@ -3991,13 +4436,30 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3991
4436
  * - Available status of the document for the current locale
3992
4437
  */
3993
4438
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
3994
- if (!document)
3995
- return document;
4439
+ if (!document) {
4440
+ return {
4441
+ data: document,
4442
+ meta: {
4443
+ availableLocales: [],
4444
+ availableStatus: []
4445
+ }
4446
+ };
4447
+ }
3996
4448
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
3997
4449
  if (!hasDraftAndPublish) {
3998
4450
  opts.availableStatus = false;
3999
4451
  }
4000
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
+ }
4001
4463
  return {
4002
4464
  data: {
4003
4465
  ...document,
@@ -4042,26 +4504,9 @@ const sumDraftCounts = (entity, uid2) => {
4042
4504
  }, 0);
4043
4505
  };
4044
4506
  const { ApplicationError } = strapiUtils.errors;
4045
- const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = ALLOWED_WEBHOOK_EVENTS;
4046
4507
  const { PUBLISHED_AT_ATTRIBUTE } = strapiUtils.contentTypes.constants;
4047
4508
  const omitPublishedAtField = fp.omit(PUBLISHED_AT_ATTRIBUTE);
4048
4509
  const omitIdField = fp.omit("id");
4049
- const emitEvent = async (uid2, event, document) => {
4050
- const modelDef = strapi.getModel(uid2);
4051
- const sanitizedDocument = await strapiUtils.sanitize.sanitizers.defaultSanitizeOutput(
4052
- {
4053
- schema: modelDef,
4054
- getModel(uid22) {
4055
- return strapi.getModel(uid22);
4056
- }
4057
- },
4058
- document
4059
- );
4060
- strapi.eventHub.emit(event, {
4061
- model: modelDef.modelName,
4062
- entry: sanitizedDocument
4063
- });
4064
- };
4065
4510
  const documentManager = ({ strapi: strapi2 }) => {
4066
4511
  return {
4067
4512
  async findOne(id, uid2, opts = {}) {
@@ -4080,6 +4525,9 @@ const documentManager = ({ strapi: strapi2 }) => {
4080
4525
  } else if (opts.locale && opts.locale !== "*") {
4081
4526
  where.locale = opts.locale;
4082
4527
  }
4528
+ if (typeof opts.isPublished === "boolean") {
4529
+ where.publishedAt = { $notNull: opts.isPublished };
4530
+ }
4083
4531
  return strapi2.db.query(uid2).findMany({ populate: opts.populate, where });
4084
4532
  },
4085
4533
  async findMany(opts, uid2) {
@@ -4113,10 +4561,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4113
4561
  async clone(id, body, uid2) {
4114
4562
  const populate = await buildDeepPopulate(uid2);
4115
4563
  const params = {
4116
- data: {
4117
- ...omitIdField(body),
4118
- [PUBLISHED_AT_ATTRIBUTE]: null
4119
- },
4564
+ data: omitIdField(body),
4120
4565
  populate
4121
4566
  };
4122
4567
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4142,70 +4587,36 @@ const documentManager = ({ strapi: strapi2 }) => {
4142
4587
  return {};
4143
4588
  },
4144
4589
  // FIXME: handle relations
4145
- async deleteMany(opts, uid2) {
4146
- const docs = await strapi2.documents(uid2).findMany(opts);
4147
- for (const doc of docs) {
4148
- await strapi2.documents(uid2).delete({ documentId: doc.documentId });
4149
- }
4150
- return { count: docs.length };
4590
+ async deleteMany(documentIds, uid2, opts = {}) {
4591
+ const deletedEntries = await strapi2.db.transaction(async () => {
4592
+ return Promise.all(documentIds.map(async (id) => this.delete(id, uid2, opts)));
4593
+ });
4594
+ return { count: deletedEntries.length };
4151
4595
  },
4152
4596
  async publish(id, uid2, opts = {}) {
4153
4597
  const populate = await buildDeepPopulate(uid2);
4154
4598
  const params = { ...opts, populate };
4155
- return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries.at(0));
4599
+ return strapi2.documents(uid2).publish({ ...params, documentId: id }).then((result) => result?.entries);
4156
4600
  },
4157
- async publishMany(entities, uid2) {
4158
- if (!entities.length) {
4159
- return null;
4160
- }
4161
- await Promise.all(
4162
- entities.map((document) => {
4163
- return strapi2.entityValidator.validateEntityCreation(
4164
- strapi2.getModel(uid2),
4165
- document,
4166
- void 0,
4167
- // @ts-expect-error - FIXME: entity here is unnecessary
4168
- document
4169
- );
4170
- })
4171
- );
4172
- const entitiesToPublish = entities.filter((doc) => !doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4173
- const filters = { id: { $in: entitiesToPublish } };
4174
- const data = { [PUBLISHED_AT_ATTRIBUTE]: /* @__PURE__ */ new Date() };
4175
- const populate = await buildDeepPopulate(uid2);
4176
- const publishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4177
- where: filters,
4178
- data
4179
- });
4180
- const publishedEntities = await strapi2.db.query(uid2).findMany({
4181
- where: filters,
4182
- populate
4601
+ async publishMany(uid2, documentIds, locale) {
4602
+ return strapi2.db.transaction(async () => {
4603
+ const results = await Promise.all(
4604
+ documentIds.map((documentId) => this.publish(documentId, uid2, { locale }))
4605
+ );
4606
+ const publishedEntitiesCount = results.flat().filter(Boolean).length;
4607
+ return publishedEntitiesCount;
4183
4608
  });
4184
- await Promise.all(
4185
- publishedEntities.map((doc) => emitEvent(uid2, ENTRY_PUBLISH, doc))
4186
- );
4187
- return publishedEntitiesCount;
4188
4609
  },
4189
- async unpublishMany(documents, uid2) {
4190
- if (!documents.length) {
4191
- return null;
4192
- }
4193
- const entitiesToUnpublish = documents.filter((doc) => doc[PUBLISHED_AT_ATTRIBUTE]).map((doc) => doc.id);
4194
- const filters = { id: { $in: entitiesToUnpublish } };
4195
- const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
4196
- const populate = await buildDeepPopulate(uid2);
4197
- const unpublishedEntitiesCount = await strapi2.db.query(uid2).updateMany({
4198
- where: filters,
4199
- data
4200
- });
4201
- const unpublishedEntities = await strapi2.db.query(uid2).findMany({
4202
- where: filters,
4203
- populate
4610
+ async unpublishMany(documentIds, uid2, opts = {}) {
4611
+ const unpublishedEntries = await strapi2.db.transaction(async () => {
4612
+ return Promise.all(
4613
+ documentIds.map(
4614
+ (id) => strapi2.documents(uid2).unpublish({ ...opts, documentId: id }).then((result) => result?.entries)
4615
+ )
4616
+ );
4204
4617
  });
4205
- await Promise.all(
4206
- unpublishedEntities.map((doc) => emitEvent(uid2, ENTRY_UNPUBLISH, doc))
4207
- );
4208
- return unpublishedEntitiesCount;
4618
+ const unpublishedEntitiesCount = unpublishedEntries.flat().filter(Boolean).length;
4619
+ return { count: unpublishedEntitiesCount };
4209
4620
  },
4210
4621
  async unpublish(id, uid2, opts = {}) {
4211
4622
  const populate = await buildDeepPopulate(uid2);
@@ -4230,16 +4641,20 @@ const documentManager = ({ strapi: strapi2 }) => {
4230
4641
  }
4231
4642
  return sumDraftCounts(document, uid2);
4232
4643
  },
4233
- async countManyEntriesDraftRelations(ids, uid2, locale) {
4644
+ async countManyEntriesDraftRelations(documentIds, uid2, locale) {
4234
4645
  const { populate, hasRelations } = getDeepPopulateDraftCount(uid2);
4235
4646
  if (!hasRelations) {
4236
4647
  return 0;
4237
4648
  }
4649
+ let localeFilter = {};
4650
+ if (locale) {
4651
+ localeFilter = Array.isArray(locale) ? { locale: { $in: locale } } : { locale };
4652
+ }
4238
4653
  const entities = await strapi2.db.query(uid2).findMany({
4239
4654
  populate,
4240
4655
  where: {
4241
- id: { $in: ids },
4242
- ...locale ? { locale } : {}
4656
+ documentId: { $in: documentIds },
4657
+ ...localeFilter
4243
4658
  }
4244
4659
  });
4245
4660
  const totalNumberDraftRelations = entities.reduce(
@@ -4262,7 +4677,8 @@ const services = {
4262
4677
  permission,
4263
4678
  "populate-builder": populateBuilder$1,
4264
4679
  uid,
4265
- ...history.services ? history.services : {}
4680
+ ...history.services ? history.services : {},
4681
+ ...preview.services ? preview.services : {}
4266
4682
  };
4267
4683
  const index = () => {
4268
4684
  return {