@strapi/content-manager 0.0.0-experimental.f75e3c6d67cc47c64ab37479efdbb7b43be50b78 → 0.0.0-experimental.f9cac24ba3b2f6acb12d0fb5669106e5a134174e

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 (144) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js → ComponentConfigurationPage-3feZ0gyp.js} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js.map → ComponentConfigurationPage-3feZ0gyp.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs → ComponentConfigurationPage-DkUdgHD9.mjs} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs.map → ComponentConfigurationPage-DkUdgHD9.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js → EditConfigurationPage-B0KA-x9U.js} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js.map → EditConfigurationPage-B0KA-x9U.js.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs → EditConfigurationPage-Ox5wFgpq.mjs} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs.map → EditConfigurationPage-Ox5wFgpq.mjs.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-ChgloMyO.js → EditViewPage-OMv9CogC.js} +68 -47
  11. package/dist/_chunks/EditViewPage-OMv9CogC.js.map +1 -0
  12. package/dist/_chunks/{EditViewPage-dFPBya9U.mjs → EditViewPage-foKE8Al3.mjs} +69 -48
  13. package/dist/_chunks/EditViewPage-foKE8Al3.mjs.map +1 -0
  14. package/dist/_chunks/{Field-C1nUKcdS.mjs → Field-CLqZcnnc.mjs} +579 -227
  15. package/dist/_chunks/Field-CLqZcnnc.mjs.map +1 -0
  16. package/dist/_chunks/{Field-dLk-vgLL.js → Field-u09MCk3G.js} +581 -229
  17. package/dist/_chunks/Field-u09MCk3G.js.map +1 -0
  18. package/dist/_chunks/{Form-CbXtmHC_.js → Form-B9c_Ti0q.js} +52 -34
  19. package/dist/_chunks/Form-B9c_Ti0q.js.map +1 -0
  20. package/dist/_chunks/{Form-DOlpi7Js.mjs → Form-CU4hRyJf.mjs} +54 -36
  21. package/dist/_chunks/Form-CU4hRyJf.mjs.map +1 -0
  22. package/dist/_chunks/{History-BFNUAiGc.mjs → History-BFyFzpSS.mjs} +160 -42
  23. package/dist/_chunks/History-BFyFzpSS.mjs.map +1 -0
  24. package/dist/_chunks/{History-BjDfohBr.js → History-OlickLyX.js} +159 -41
  25. package/dist/_chunks/History-OlickLyX.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-DDi0KqFm.mjs → ListConfigurationPage-Bu5Z_39o.mjs} +58 -48
  27. package/dist/_chunks/ListConfigurationPage-Bu5Z_39o.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-IQBgWTaa.js → ListConfigurationPage-D0AAi_cW.js} +57 -46
  29. package/dist/_chunks/ListConfigurationPage-D0AAi_cW.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-CZYGqlvF.js → ListViewPage--lV5p8Qi.js} +117 -104
  31. package/dist/_chunks/ListViewPage--lV5p8Qi.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-BPjljUsH.mjs → ListViewPage-BAHxSPux.mjs} +116 -103
  33. package/dist/_chunks/ListViewPage-BAHxSPux.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs → NoContentTypePage-C6SMXW77.mjs} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs.map → NoContentTypePage-C6SMXW77.mjs.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js → NoContentTypePage-Dxl9oZqL.js} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js.map → NoContentTypePage-Dxl9oZqL.js.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js → NoPermissionsPage-BY1-rMng.js} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js.map → NoPermissionsPage-BY1-rMng.js.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs → NoPermissionsPage-o9BXzQeI.mjs} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs.map → NoPermissionsPage-o9BXzQeI.mjs.map} +1 -1
  42. package/dist/_chunks/{Relations-DTowyge2.mjs → Relations-BAK95JHc.mjs} +34 -25
  43. package/dist/_chunks/Relations-BAK95JHc.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DU6B7irU.js → Relations-CHfwGkBG.js} +34 -25
  45. package/dist/_chunks/Relations-CHfwGkBG.js.map +1 -0
  46. package/dist/_chunks/{en-DTULi5-d.js → en-Bm0D0IWz.js} +21 -15
  47. package/dist/_chunks/{en-DTULi5-d.js.map → en-Bm0D0IWz.js.map} +1 -1
  48. package/dist/_chunks/{en-GCOTL6jR.mjs → en-DKV44jRb.mjs} +21 -15
  49. package/dist/_chunks/{en-GCOTL6jR.mjs.map → en-DKV44jRb.mjs.map} +1 -1
  50. package/dist/_chunks/{index-BaGHmIir.mjs → index-CxlpxzA5.mjs} +1401 -779
  51. package/dist/_chunks/index-CxlpxzA5.mjs.map +1 -0
  52. package/dist/_chunks/{index-CCJeB7Rw.js → index-_Mlmsefd.js} +1368 -746
  53. package/dist/_chunks/index-_Mlmsefd.js.map +1 -0
  54. package/dist/_chunks/{layout-BinjszSQ.mjs → layout-Cr0H40au.mjs} +41 -23
  55. package/dist/_chunks/layout-Cr0H40au.mjs.map +1 -0
  56. package/dist/_chunks/{layout-ni_L9kT1.js → layout-vcHVgSr1.js} +39 -21
  57. package/dist/_chunks/layout-vcHVgSr1.js.map +1 -0
  58. package/dist/_chunks/{relations-c91ji5eR.mjs → relations-Dq60voyX.mjs} +2 -2
  59. package/dist/_chunks/{relations-c91ji5eR.mjs.map → relations-Dq60voyX.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CeJAJc5I.js → relations-hXUB80SH.js} +2 -2
  61. package/dist/_chunks/{relations-CeJAJc5I.js.map → relations-hXUB80SH.js.map} +1 -1
  62. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  63. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  64. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  65. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  66. package/dist/admin/index.js +2 -1
  67. package/dist/admin/index.js.map +1 -1
  68. package/dist/admin/index.mjs +7 -6
  69. package/dist/admin/src/exports.d.ts +1 -1
  70. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  71. package/dist/admin/src/history/index.d.ts +3 -0
  72. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  73. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  74. package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -1
  75. package/dist/admin/src/index.d.ts +1 -0
  76. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  77. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  78. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  79. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  80. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  81. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  82. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  83. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  84. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  85. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +14 -0
  86. package/dist/admin/src/preview/constants.d.ts +1 -0
  87. package/dist/admin/src/preview/index.d.ts +4 -0
  88. package/dist/admin/src/services/api.d.ts +1 -1
  89. package/dist/admin/src/services/components.d.ts +2 -2
  90. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  91. package/dist/admin/src/services/documents.d.ts +19 -17
  92. package/dist/admin/src/services/init.d.ts +1 -1
  93. package/dist/admin/src/services/relations.d.ts +2 -2
  94. package/dist/admin/src/services/uid.d.ts +3 -3
  95. package/dist/admin/src/utils/validation.d.ts +4 -1
  96. package/dist/server/index.js +233 -128
  97. package/dist/server/index.js.map +1 -1
  98. package/dist/server/index.mjs +234 -129
  99. package/dist/server/index.mjs.map +1 -1
  100. package/dist/server/src/bootstrap.d.ts.map +1 -1
  101. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  102. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  103. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  104. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  105. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  106. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  107. package/dist/server/src/history/services/history.d.ts.map +1 -1
  108. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  109. package/dist/server/src/history/services/utils.d.ts +2 -1
  110. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  111. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  112. package/dist/server/src/preview/constants.d.ts +2 -0
  113. package/dist/server/src/preview/constants.d.ts.map +1 -0
  114. package/dist/server/src/preview/index.d.ts +4 -0
  115. package/dist/server/src/preview/index.d.ts.map +1 -0
  116. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  117. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  118. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  119. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  120. package/dist/shared/contracts/collection-types.d.ts +3 -1
  121. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  122. package/package.json +13 -13
  123. package/dist/_chunks/EditViewPage-ChgloMyO.js.map +0 -1
  124. package/dist/_chunks/EditViewPage-dFPBya9U.mjs.map +0 -1
  125. package/dist/_chunks/Field-C1nUKcdS.mjs.map +0 -1
  126. package/dist/_chunks/Field-dLk-vgLL.js.map +0 -1
  127. package/dist/_chunks/Form-CbXtmHC_.js.map +0 -1
  128. package/dist/_chunks/Form-DOlpi7Js.mjs.map +0 -1
  129. package/dist/_chunks/History-BFNUAiGc.mjs.map +0 -1
  130. package/dist/_chunks/History-BjDfohBr.js.map +0 -1
  131. package/dist/_chunks/ListConfigurationPage-DDi0KqFm.mjs.map +0 -1
  132. package/dist/_chunks/ListConfigurationPage-IQBgWTaa.js.map +0 -1
  133. package/dist/_chunks/ListViewPage-BPjljUsH.mjs.map +0 -1
  134. package/dist/_chunks/ListViewPage-CZYGqlvF.js.map +0 -1
  135. package/dist/_chunks/Relations-DTowyge2.mjs.map +0 -1
  136. package/dist/_chunks/Relations-DU6B7irU.js.map +0 -1
  137. package/dist/_chunks/index-BaGHmIir.mjs.map +0 -1
  138. package/dist/_chunks/index-CCJeB7Rw.js.map +0 -1
  139. package/dist/_chunks/layout-BinjszSQ.mjs.map +0 -1
  140. package/dist/_chunks/layout-ni_L9kT1.js.map +0 -1
  141. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  142. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  143. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  144. package/strapi-server.js +0 -3
@@ -199,7 +199,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
199
199
  return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
200
200
  };
201
201
  const localesService = strapi2.plugin("i18n")?.service("locales");
202
+ const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
202
203
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
204
+ const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
203
205
  const getLocaleDictionary = async () => {
204
206
  if (!localesService)
205
207
  return {};
@@ -226,20 +228,25 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
226
228
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
227
229
  return documentMetadataService.getStatus(document, meta.availableStatus);
228
230
  };
229
- const getDeepPopulate2 = (uid2) => {
231
+ const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
230
232
  const model = strapi2.getModel(uid2);
231
233
  const attributes = Object.entries(model.attributes);
234
+ const fieldSelector = useDatabaseSyntax ? "select" : "fields";
232
235
  return attributes.reduce((acc, [attributeName, attribute]) => {
233
236
  switch (attribute.type) {
234
237
  case "relation": {
238
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
239
+ if (isMorphRelation) {
240
+ break;
241
+ }
235
242
  const isVisible2 = strapiUtils.contentTypes.isVisibleAttribute(model, attributeName);
236
243
  if (isVisible2) {
237
- acc[attributeName] = { fields: ["documentId", "locale", "publishedAt"] };
244
+ acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
238
245
  }
239
246
  break;
240
247
  }
241
248
  case "media": {
242
- acc[attributeName] = { fields: ["id"] };
249
+ acc[attributeName] = { [fieldSelector]: ["id"] };
243
250
  break;
244
251
  }
245
252
  case "component": {
@@ -312,6 +319,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
312
319
  getRelationRestoreValue,
313
320
  getMediaRestoreValue,
314
321
  getDefaultLocale,
322
+ isLocalizedContentType,
315
323
  getLocaleDictionary,
316
324
  getRetentionDays,
317
325
  getVersionStatus,
@@ -334,7 +342,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
334
342
  });
335
343
  },
336
344
  async findVersionsPage(params) {
337
- const locale = params.query.locale || await serviceUtils.getDefaultLocale();
345
+ const model = strapi2.getModel(params.query.contentType);
346
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
347
+ const defaultLocale = await serviceUtils.getDefaultLocale();
348
+ let locale = null;
349
+ if (isLocalizedContentType) {
350
+ locale = params.query.locale || defaultLocale;
351
+ }
338
352
  const [{ results, pagination }, localeDictionary] = await Promise.all([
339
353
  query.findPage({
340
354
  ...params.query,
@@ -379,7 +393,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
379
393
  if (userToPopulate == null) {
380
394
  return null;
381
395
  }
382
- return strapi2.query("admin::user").findOne({ where: { id: userToPopulate.id } });
396
+ return strapi2.query("admin::user").findOne({
397
+ where: {
398
+ ...userToPopulate.id ? { id: userToPopulate.id } : {},
399
+ ...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
400
+ }
401
+ });
383
402
  })
384
403
  );
385
404
  return {
@@ -490,13 +509,47 @@ const createHistoryService = ({ strapi: strapi2 }) => {
490
509
  }
491
510
  };
492
511
  };
512
+ const shouldCreateHistoryVersion = (context) => {
513
+ if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
514
+ return false;
515
+ }
516
+ if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
517
+ return false;
518
+ }
519
+ if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
520
+ return false;
521
+ }
522
+ if (!context.contentType.uid.startsWith("api::")) {
523
+ return false;
524
+ }
525
+ return true;
526
+ };
527
+ const getSchemas = (uid2) => {
528
+ const attributesSchema = strapi.getModel(uid2).attributes;
529
+ const componentsSchemas = Object.keys(attributesSchema).reduce(
530
+ (currentComponentSchemas, key) => {
531
+ const fieldSchema = attributesSchema[key];
532
+ if (fieldSchema.type === "component") {
533
+ const componentSchema = strapi.getModel(fieldSchema.component).attributes;
534
+ return {
535
+ ...currentComponentSchemas,
536
+ [fieldSchema.component]: componentSchema
537
+ };
538
+ }
539
+ return currentComponentSchemas;
540
+ },
541
+ {}
542
+ );
543
+ return {
544
+ schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
545
+ componentsSchemas
546
+ };
547
+ };
493
548
  const createLifecyclesService = ({ strapi: strapi2 }) => {
494
549
  const state = {
495
550
  deleteExpiredJob: null,
496
551
  isInitialized: false
497
552
  };
498
- const query = strapi2.db.query(HISTORY_VERSION_UID);
499
- const historyService = getService(strapi2, "history");
500
553
  const serviceUtils = createServiceUtils({ strapi: strapi2 });
501
554
  return {
502
555
  async bootstrap() {
@@ -504,66 +557,53 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
504
557
  return;
505
558
  }
506
559
  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
560
  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 };
561
+ if (!shouldCreateHistoryVersion(context)) {
562
+ return result;
563
+ }
564
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
519
565
  const defaultLocale = await serviceUtils.getDefaultLocale();
520
- const locale = documentContext.locale || defaultLocale;
521
- if (Array.isArray(locale)) {
522
- strapi2.log.warn(
523
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
524
- );
525
- return next();
566
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
567
+ if (!locales.length) {
568
+ return result;
526
569
  }
527
- const document = await strapi2.documents(contentTypeUid).findOne({
528
- documentId: documentContext.documentId,
529
- locale,
530
- populate: serviceUtils.getDeepPopulate(contentTypeUid)
570
+ const uid2 = context.contentType.uid;
571
+ const schemas = getSchemas(uid2);
572
+ const model = strapi2.getModel(uid2);
573
+ const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
574
+ const localeEntries = await strapi2.db.query(uid2).findMany({
575
+ where: {
576
+ documentId,
577
+ ...isLocalizedContentType ? { locale: { $in: locales } } : {},
578
+ ...strapiUtils.contentTypes.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
579
+ },
580
+ populate: serviceUtils.getDeepPopulate(
581
+ uid2,
582
+ true
583
+ /* use database syntax */
584
+ )
531
585
  });
532
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
533
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
534
- const componentsSchemas = Object.keys(
535
- attributesSchema
536
- ).reduce((currentComponentSchemas, key) => {
537
- const fieldSchema = attributesSchema[key];
538
- if (fieldSchema.type === "component") {
539
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
540
- return {
541
- ...currentComponentSchemas,
542
- [fieldSchema.component]: componentSchema
543
- };
544
- }
545
- return currentComponentSchemas;
546
- }, {});
547
586
  await strapi2.db.transaction(async ({ onCommit }) => {
548
- onCommit(() => {
549
- historyService.createVersion({
550
- contentType: contentTypeUid,
551
- data: fp.omit(FIELDS_TO_IGNORE, document),
552
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
553
- componentsSchemas,
554
- relatedDocumentId: documentContext.documentId,
555
- locale,
556
- status
557
- });
587
+ onCommit(async () => {
588
+ for (const entry of localeEntries) {
589
+ const status = await serviceUtils.getVersionStatus(uid2, entry);
590
+ await getService(strapi2, "history").createVersion({
591
+ contentType: uid2,
592
+ data: fp.omit(FIELDS_TO_IGNORE, entry),
593
+ relatedDocumentId: documentId,
594
+ locale: entry.locale,
595
+ status,
596
+ ...schemas
597
+ });
598
+ }
558
599
  });
559
600
  });
560
601
  return result;
561
602
  });
562
- const retentionDays = serviceUtils.getRetentionDays();
563
603
  state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
564
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
604
+ const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1e3;
565
605
  const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
566
- query.deleteMany({
606
+ strapi2.db.query(HISTORY_VERSION_UID).deleteMany({
567
607
  where: {
568
608
  created_at: {
569
609
  $lt: expirationDate.toISOString()
@@ -655,7 +695,7 @@ const historyVersion = {
655
695
  }
656
696
  }
657
697
  };
658
- const getFeature = () => {
698
+ const getFeature$1 = () => {
659
699
  if (strapi.ee.features.isEnabled("cms-content-history")) {
660
700
  return {
661
701
  register({ strapi: strapi2 }) {
@@ -678,7 +718,7 @@ const getFeature = () => {
678
718
  }
679
719
  };
680
720
  };
681
- const history = getFeature();
721
+ const history = getFeature$1();
682
722
  const register = async ({ strapi: strapi2 }) => {
683
723
  await history.register?.({ strapi: strapi2 });
684
724
  };
@@ -686,6 +726,18 @@ const ALLOWED_WEBHOOK_EVENTS = {
686
726
  ENTRY_PUBLISH: "entry.publish",
687
727
  ENTRY_UNPUBLISH: "entry.unpublish"
688
728
  };
729
+ const FEATURE_ID = "preview";
730
+ const getFeature = () => {
731
+ if (!strapi.features.future.isEnabled(FEATURE_ID)) {
732
+ return {};
733
+ }
734
+ return {
735
+ bootstrap() {
736
+ console.log("Bootstrapping preview server");
737
+ }
738
+ };
739
+ };
740
+ const preview = getFeature();
689
741
  const bootstrap = async () => {
690
742
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
691
743
  strapi.get("webhookStore").addAllowedEvent(key, value);
@@ -695,6 +747,7 @@ const bootstrap = async () => {
695
747
  await getService$1("content-types").syncConfigurations();
696
748
  await getService$1("permission").registerPermissions();
697
749
  await history.bootstrap?.({ strapi });
750
+ await preview.bootstrap?.({ strapi });
698
751
  };
699
752
  const destroy = async ({ strapi: strapi2 }) => {
700
753
  await history.destroy?.({ strapi: strapi2 });
@@ -1195,6 +1248,11 @@ const { createPolicy } = strapiUtils.policy;
1195
1248
  const hasPermissions = createPolicy({
1196
1249
  name: "plugin::content-manager.hasPermissions",
1197
1250
  validator: validateHasPermissionsInput,
1251
+ /**
1252
+ * NOTE: Action aliases are currently not checked at this level (policy).
1253
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1254
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1255
+ */
1198
1256
  handler(ctx, config = {}) {
1199
1257
  const { actions = [], hasAtLeastOne = false } = config;
1200
1258
  const { userAbility } = ctx.state;
@@ -1588,9 +1646,11 @@ const multipleLocaleSchema = strapiUtils.yup.lazy(
1588
1646
  (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1589
1647
  );
1590
1648
  const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1591
- const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1649
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1592
1650
  const { allowMultipleLocales } = opts;
1593
- const { locale, status, ...rest } = request || {};
1651
+ const { locale, status: providedStatus, ...rest } = request || {};
1652
+ const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1653
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1594
1654
  const schema = strapiUtils.yup.object().shape({
1595
1655
  locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1596
1656
  status: statusSchema
@@ -1638,7 +1698,7 @@ const createDocument = async (ctx, opts) => {
1638
1698
  const setCreator = strapiUtils.setCreatorFields({ user });
1639
1699
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1640
1700
  const sanitizedBody = await sanitizeFn(body);
1641
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1701
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1642
1702
  return documentManager2.create(model, {
1643
1703
  data: sanitizedBody,
1644
1704
  locale,
@@ -1657,7 +1717,7 @@ const updateDocument = async (ctx, opts) => {
1657
1717
  }
1658
1718
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1659
1719
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1660
- const { locale } = await getDocumentLocaleAndStatus(body);
1720
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1661
1721
  const [documentVersion, documentExists] = await Promise.all([
1662
1722
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1663
1723
  documentManager2.exists(model, id)
@@ -1673,7 +1733,7 @@ const updateDocument = async (ctx, opts) => {
1673
1733
  throw new strapiUtils.errors.ForbiddenError();
1674
1734
  }
1675
1735
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1676
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1736
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1677
1737
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1678
1738
  const sanitizedBody = await sanitizeFn(body);
1679
1739
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1695,7 +1755,7 @@ const collectionTypes = {
1695
1755
  }
1696
1756
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1697
1757
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1698
- const { locale, status } = await getDocumentLocaleAndStatus(query);
1758
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1699
1759
  const { results: documents, pagination } = await documentManager2.findPage(
1700
1760
  { ...permissionQuery, populate, locale, status },
1701
1761
  model
@@ -1730,7 +1790,7 @@ const collectionTypes = {
1730
1790
  }
1731
1791
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1732
1792
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1733
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1793
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1734
1794
  const version = await documentManager2.findOne(id, model, {
1735
1795
  populate,
1736
1796
  locale,
@@ -1745,7 +1805,7 @@ const collectionTypes = {
1745
1805
  permissionChecker2,
1746
1806
  model,
1747
1807
  // @ts-expect-error TODO: fix
1748
- { id, locale, publishedAt: null },
1808
+ { documentId: id, locale, publishedAt: null },
1749
1809
  { availableLocales: true, availableStatus: false }
1750
1810
  );
1751
1811
  ctx.body = { data: {}, meta };
@@ -1797,7 +1857,7 @@ const collectionTypes = {
1797
1857
  }
1798
1858
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1799
1859
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1800
- const { locale } = await getDocumentLocaleAndStatus(body);
1860
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1801
1861
  const document = await documentManager2.findOne(id, model, {
1802
1862
  populate,
1803
1863
  locale,
@@ -1842,7 +1902,7 @@ const collectionTypes = {
1842
1902
  }
1843
1903
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1844
1904
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1845
- const { locale } = await getDocumentLocaleAndStatus(ctx.query);
1905
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1846
1906
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1847
1907
  if (documentLocales.length === 0) {
1848
1908
  return ctx.notFound();
@@ -1871,11 +1931,34 @@ const collectionTypes = {
1871
1931
  const publishedDocument = await strapi.db.transaction(async () => {
1872
1932
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1873
1933
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1874
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
1934
+ let document;
1935
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1936
+ const isCreate = fp.isNil(id);
1937
+ if (isCreate) {
1938
+ if (permissionChecker2.cannot.create()) {
1939
+ throw new strapiUtils.errors.ForbiddenError();
1940
+ }
1941
+ document = await createDocument(ctx, { populate });
1942
+ }
1943
+ const isUpdate = !isCreate;
1944
+ if (isUpdate) {
1945
+ const documentExists = documentManager2.exists(model, id);
1946
+ if (!documentExists) {
1947
+ throw new strapiUtils.errors.NotFoundError("Document not found");
1948
+ }
1949
+ document = await documentManager2.findOne(id, model, { populate, locale });
1950
+ if (!document) {
1951
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
1952
+ throw new strapiUtils.errors.ForbiddenError();
1953
+ }
1954
+ document = await updateDocument(ctx);
1955
+ } else if (permissionChecker2.can.update(document)) {
1956
+ await updateDocument(ctx);
1957
+ }
1958
+ }
1875
1959
  if (permissionChecker2.cannot.publish(document)) {
1876
1960
  throw new strapiUtils.errors.ForbiddenError();
1877
1961
  }
1878
- const { locale } = await getDocumentLocaleAndStatus(body);
1879
1962
  const publishResult = await documentManager2.publish(document.documentId, model, {
1880
1963
  locale
1881
1964
  // TODO: Allow setting creator fields on publish
@@ -1902,7 +1985,9 @@ const collectionTypes = {
1902
1985
  }
1903
1986
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1904
1987
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1905
- const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
1988
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
1989
+ allowMultipleLocales: true
1990
+ });
1906
1991
  const entityPromises = documentIds.map(
1907
1992
  (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1908
1993
  );
@@ -1929,7 +2014,9 @@ const collectionTypes = {
1929
2014
  if (permissionChecker2.cannot.unpublish()) {
1930
2015
  return ctx.forbidden();
1931
2016
  }
1932
- const { locale } = await getDocumentLocaleAndStatus(body);
2017
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2018
+ allowMultipleLocales: true
2019
+ });
1933
2020
  const entityPromises = documentIds.map(
1934
2021
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1935
2022
  );
@@ -1962,7 +2049,7 @@ const collectionTypes = {
1962
2049
  }
1963
2050
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1964
2051
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1965
- const { locale } = await getDocumentLocaleAndStatus(body);
2052
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1966
2053
  const document = await documentManager2.findOne(id, model, {
1967
2054
  populate,
1968
2055
  locale,
@@ -1999,7 +2086,7 @@ const collectionTypes = {
1999
2086
  }
2000
2087
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2001
2088
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2002
- const { locale } = await getDocumentLocaleAndStatus(body);
2089
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2003
2090
  const document = await documentManager2.findOne(id, model, {
2004
2091
  populate,
2005
2092
  locale,
@@ -2030,7 +2117,7 @@ const collectionTypes = {
2030
2117
  }
2031
2118
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2032
2119
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2033
- const { locale } = await getDocumentLocaleAndStatus(body);
2120
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2034
2121
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2035
2122
  populate,
2036
2123
  locale
@@ -2057,7 +2144,7 @@ const collectionTypes = {
2057
2144
  }
2058
2145
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2059
2146
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2060
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
2147
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2061
2148
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2062
2149
  if (!entity) {
2063
2150
  return ctx.notFound();
@@ -2080,7 +2167,7 @@ const collectionTypes = {
2080
2167
  if (permissionChecker2.cannot.read()) {
2081
2168
  return ctx.forbidden();
2082
2169
  }
2083
- const entities = await documentManager2.findMany(
2170
+ const documents = await documentManager2.findMany(
2084
2171
  {
2085
2172
  filters: {
2086
2173
  documentId: ids
@@ -2089,7 +2176,7 @@ const collectionTypes = {
2089
2176
  },
2090
2177
  model
2091
2178
  );
2092
- if (!entities) {
2179
+ if (!documents) {
2093
2180
  return ctx.notFound();
2094
2181
  }
2095
2182
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2280,20 +2367,13 @@ const sanitizeMainField = (model, mainField, userAbility) => {
2280
2367
  userAbility,
2281
2368
  model: model.uid
2282
2369
  });
2283
- if (!isListable(model, mainField)) {
2370
+ const isMainFieldListable = isListable(model, mainField);
2371
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2372
+ if (!isMainFieldListable || !canReadMainField) {
2284
2373
  return "id";
2285
2374
  }
2286
- if (permissionChecker2.cannot.read(null, mainField)) {
2287
- if (model.uid === "plugin::users-permissions.role") {
2288
- const userPermissionChecker = getService$1("permission-checker").create({
2289
- userAbility,
2290
- model: "plugin::users-permissions.user"
2291
- });
2292
- if (userPermissionChecker.can.read()) {
2293
- return "name";
2294
- }
2295
- }
2296
- return "id";
2375
+ if (model.uid === "plugin::users-permissions.role") {
2376
+ return "name";
2297
2377
  }
2298
2378
  return mainField;
2299
2379
  };
@@ -2326,11 +2406,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2326
2406
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2327
2407
  const isSourceLocalized = isLocalized(sourceModel);
2328
2408
  const isTargetLocalized = isLocalized(targetModel);
2329
- let validatedLocale = locale;
2330
- if (!targetModel || !isTargetLocalized)
2331
- validatedLocale = void 0;
2332
2409
  return {
2333
- locale: validatedLocale,
2410
+ locale,
2334
2411
  isSourceLocalized,
2335
2412
  isTargetLocalized
2336
2413
  };
@@ -2433,7 +2510,7 @@ const relations = {
2433
2510
  attribute,
2434
2511
  fieldsToSelect,
2435
2512
  mainField,
2436
- source: { schema: sourceSchema },
2513
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2437
2514
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2438
2515
  sourceSchema,
2439
2516
  targetSchema,
@@ -2455,7 +2532,8 @@ const relations = {
2455
2532
  fieldsToSelect,
2456
2533
  mainField,
2457
2534
  source: {
2458
- schema: { uid: sourceUid, modelType: sourceModelType }
2535
+ schema: { uid: sourceUid, modelType: sourceModelType },
2536
+ isLocalized: isSourceLocalized
2459
2537
  },
2460
2538
  target: {
2461
2539
  schema: { uid: targetUid },
@@ -2493,12 +2571,16 @@ const relations = {
2493
2571
  } else {
2494
2572
  where.id = id;
2495
2573
  }
2496
- if (status) {
2497
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2574
+ const publishedAt = getPublishedAtClause(status, targetUid);
2575
+ if (!fp.isEmpty(publishedAt)) {
2576
+ where[`${alias}.published_at`] = publishedAt;
2498
2577
  }
2499
- if (filterByLocale) {
2578
+ if (isTargetLocalized && locale) {
2500
2579
  where[`${alias}.locale`] = locale;
2501
2580
  }
2581
+ if (isSourceLocalized && locale) {
2582
+ where.locale = locale;
2583
+ }
2502
2584
  if ((idsToInclude?.length ?? 0) !== 0) {
2503
2585
  where[`${alias}.id`].$notIn = idsToInclude;
2504
2586
  }
@@ -2516,7 +2598,8 @@ const relations = {
2516
2598
  id: { $notIn: fp.uniq(idsToOmit) }
2517
2599
  });
2518
2600
  }
2519
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2601
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2602
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2520
2603
  ctx.body = {
2521
2604
  ...res,
2522
2605
  results: await addStatusToRelations(targetUid, res.results)
@@ -2551,9 +2634,7 @@ const relations = {
2551
2634
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2552
2635
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2553
2636
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2554
- ordering: "desc",
2555
- page: ctx.request.query.page,
2556
- pageSize: ctx.request.query.pageSize
2637
+ ordering: "desc"
2557
2638
  });
2558
2639
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2559
2640
  ctx.body = {
@@ -2585,7 +2666,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2585
2666
  throw new strapiUtils.errors.ForbiddenError();
2586
2667
  }
2587
2668
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2588
- const { locale } = await getDocumentLocaleAndStatus(body);
2669
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2589
2670
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2590
2671
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2591
2672
  // Find the first document to check if it exists
@@ -2626,7 +2707,7 @@ const singleTypes = {
2626
2707
  return ctx.forbidden();
2627
2708
  }
2628
2709
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2629
- const { locale, status } = await getDocumentLocaleAndStatus(query);
2710
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2630
2711
  const version = await findDocument(permissionQuery, model, { locale, status });
2631
2712
  if (!version) {
2632
2713
  if (permissionChecker2.cannot.create()) {
@@ -2640,7 +2721,7 @@ const singleTypes = {
2640
2721
  permissionChecker2,
2641
2722
  model,
2642
2723
  // @ts-expect-error - fix types
2643
- { id: document.documentId, locale, publishedAt: null },
2724
+ { documentId: document.documentId, locale, publishedAt: null },
2644
2725
  { availableLocales: true, availableStatus: false }
2645
2726
  );
2646
2727
  ctx.body = { data: {}, meta };
@@ -2671,7 +2752,7 @@ const singleTypes = {
2671
2752
  }
2672
2753
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2673
2754
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2674
- const { locale } = await getDocumentLocaleAndStatus(query);
2755
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2675
2756
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2676
2757
  populate,
2677
2758
  locale
@@ -2708,7 +2789,7 @@ const singleTypes = {
2708
2789
  if (permissionChecker2.cannot.publish(document)) {
2709
2790
  throw new strapiUtils.errors.ForbiddenError();
2710
2791
  }
2711
- const { locale } = await getDocumentLocaleAndStatus(document);
2792
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2712
2793
  const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2713
2794
  return publishResult.at(0);
2714
2795
  });
@@ -2731,7 +2812,7 @@ const singleTypes = {
2731
2812
  return ctx.forbidden();
2732
2813
  }
2733
2814
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2734
- const { locale } = await getDocumentLocaleAndStatus(body);
2815
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2735
2816
  const document = await findDocument(sanitizedQuery, model, { locale });
2736
2817
  if (!document) {
2737
2818
  return ctx.notFound();
@@ -2763,7 +2844,7 @@ const singleTypes = {
2763
2844
  return ctx.forbidden();
2764
2845
  }
2765
2846
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2766
- const { locale } = await getDocumentLocaleAndStatus(body);
2847
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2767
2848
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2768
2849
  if (!document) {
2769
2850
  return ctx.notFound();
@@ -2783,7 +2864,7 @@ const singleTypes = {
2783
2864
  const { query } = ctx.request;
2784
2865
  const documentManager2 = getService$1("document-manager");
2785
2866
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2786
- const { locale } = await getDocumentLocaleAndStatus(query);
2867
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2787
2868
  if (permissionChecker2.cannot.read()) {
2788
2869
  return ctx.forbidden();
2789
2870
  }
@@ -2804,7 +2885,7 @@ const uid$1 = {
2804
2885
  async generateUID(ctx) {
2805
2886
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2806
2887
  const { query = {} } = ctx.request;
2807
- const { locale } = await getDocumentLocaleAndStatus(query);
2888
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2808
2889
  await validateUIDField(contentTypeUID, field);
2809
2890
  const uidService = getService$1("uid");
2810
2891
  ctx.body = {
@@ -2816,7 +2897,7 @@ const uid$1 = {
2816
2897
  ctx.request.body
2817
2898
  );
2818
2899
  const { query = {} } = ctx.request;
2819
- const { locale } = await getDocumentLocaleAndStatus(query);
2900
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2820
2901
  await validateUIDField(contentTypeUID, field);
2821
2902
  const uidService = getService$1("uid");
2822
2903
  const isAvailable = await uidService.checkUIDAvailability({
@@ -3459,12 +3540,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3459
3540
  ability: userAbility,
3460
3541
  model
3461
3542
  });
3462
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3543
+ const { actionProvider } = strapi2.service("admin::permission");
3544
+ const toSubject = (entity) => {
3545
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3546
+ };
3463
3547
  const can = (action, entity, field) => {
3464
- return userAbility.can(action, toSubject(entity), field);
3548
+ const subject = toSubject(entity);
3549
+ const aliases = actionProvider.unstable_aliases(action, model);
3550
+ return (
3551
+ // Test the original action to see if it passes
3552
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3553
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3554
+ );
3465
3555
  };
3466
3556
  const cannot = (action, entity, field) => {
3467
- return userAbility.cannot(action, toSubject(entity), field);
3557
+ const subject = toSubject(entity);
3558
+ const aliases = actionProvider.unstable_aliases(action, model);
3559
+ return (
3560
+ // Test both the original action
3561
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3562
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3563
+ );
3468
3564
  };
3469
3565
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3470
3566
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3741,6 +3837,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3741
3837
  const attribute = model.attributes[attributeName];
3742
3838
  switch (attribute.type) {
3743
3839
  case "relation": {
3840
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
3841
+ if (isMorphRelation) {
3842
+ break;
3843
+ }
3744
3844
  if (isVisibleAttribute$1(model, attributeName)) {
3745
3845
  populateAcc[attributeName] = {
3746
3846
  count: true,
@@ -3755,22 +3855,24 @@ const getDeepPopulateDraftCount = (uid2) => {
3755
3855
  attribute.component
3756
3856
  );
3757
3857
  if (childHasRelations) {
3758
- populateAcc[attributeName] = { populate: populate2 };
3858
+ populateAcc[attributeName] = {
3859
+ populate: populate2
3860
+ };
3759
3861
  hasRelations = true;
3760
3862
  }
3761
3863
  break;
3762
3864
  }
3763
3865
  case "dynamiczone": {
3764
- const dzPopulate = (attribute.components || []).reduce((acc, componentUID) => {
3765
- const { populate: populate2, hasRelations: childHasRelations } = getDeepPopulateDraftCount(componentUID);
3766
- if (childHasRelations) {
3866
+ const dzPopulateFragment = attribute.components?.reduce((acc, componentUID) => {
3867
+ const { populate: componentPopulate, hasRelations: componentHasRelations } = getDeepPopulateDraftCount(componentUID);
3868
+ if (componentHasRelations) {
3767
3869
  hasRelations = true;
3768
- return fp.merge(acc, populate2);
3870
+ return { ...acc, [componentUID]: { populate: componentPopulate } };
3769
3871
  }
3770
3872
  return acc;
3771
3873
  }, {});
3772
- if (!fp.isEmpty(dzPopulate)) {
3773
- populateAcc[attributeName] = { populate: dzPopulate };
3874
+ if (!fp.isEmpty(dzPopulateFragment)) {
3875
+ populateAcc[attributeName] = { on: dzPopulateFragment };
3774
3876
  }
3775
3877
  break;
3776
3878
  }
@@ -4116,7 +4218,13 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4116
4218
  */
4117
4219
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4118
4220
  if (!document) {
4119
- return document;
4221
+ return {
4222
+ data: document,
4223
+ meta: {
4224
+ availableLocales: [],
4225
+ availableStatus: []
4226
+ }
4227
+ };
4120
4228
  }
4121
4229
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4122
4230
  if (!hasDraftAndPublish) {
@@ -4224,10 +4332,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4224
4332
  async clone(id, body, uid2) {
4225
4333
  const populate = await buildDeepPopulate(uid2);
4226
4334
  const params = {
4227
- data: {
4228
- ...omitIdField(body),
4229
- [PUBLISHED_AT_ATTRIBUTE]: null
4230
- },
4335
+ data: omitIdField(body),
4231
4336
  populate
4232
4337
  };
4233
4338
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));