@strapi/content-manager 0.0.0-experimental.d53e940834bf72ddc725f1d2fd36dac9abec30cb → 0.0.0-experimental.d74a8e5e655230b243e2d61ab5bec2fcdb426993

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 (169) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-CIjXcRAB.mjs} +4 -4
  3. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-CIjXcRAB.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-gsCd80MU.js} +4 -4
  5. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-gsCd80MU.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-BglmD_BF.mjs} +4 -4
  7. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-BglmD_BF.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-DHDQKBzw.js} +4 -4
  9. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-DHDQKBzw.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-C4iTxUPU.js} +30 -9
  11. package/dist/_chunks/EditViewPage-C4iTxUPU.js.map +1 -0
  12. package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-CiwVPMaK.mjs} +30 -9
  13. package/dist/_chunks/EditViewPage-CiwVPMaK.mjs.map +1 -0
  14. package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-DIjL1b5d.mjs} +249 -152
  15. package/dist/_chunks/Field-DIjL1b5d.mjs.map +1 -0
  16. package/dist/_chunks/{Field-Boxf9Ajp.js → Field-DhXEK8y1.js} +251 -154
  17. package/dist/_chunks/Field-DhXEK8y1.js.map +1 -0
  18. package/dist/_chunks/{Form-DHrru2AV.mjs → Form-CmNesrvR.mjs} +36 -17
  19. package/dist/_chunks/Form-CmNesrvR.mjs.map +1 -0
  20. package/dist/_chunks/{Form-y5g1SRsh.js → Form-CwmJ4sWe.js} +36 -17
  21. package/dist/_chunks/Form-CwmJ4sWe.js.map +1 -0
  22. package/dist/_chunks/{History-CqN6K7SX.js → History-BLCCNgCt.js} +64 -26
  23. package/dist/_chunks/History-BLCCNgCt.js.map +1 -0
  24. package/dist/_chunks/{History-Bru_KoeP.mjs → History-D-99Wh30.mjs} +65 -27
  25. package/dist/_chunks/History-D-99Wh30.mjs.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-DxWpeZrO.js} +21 -9
  27. package/dist/_chunks/ListConfigurationPage-DxWpeZrO.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-JPWZz7Kg.mjs} +21 -9
  29. package/dist/_chunks/ListConfigurationPage-JPWZz7Kg.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-CIQekSFz.js} +73 -44
  31. package/dist/_chunks/ListViewPage-CIQekSFz.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-DSK3f0ST.mjs} +71 -42
  33. package/dist/_chunks/ListViewPage-DSK3f0ST.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-C5cxKvC2.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-C5cxKvC2.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-D99LU1YP.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-D99LU1YP.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-DBrBw-0y.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-DBrBw-0y.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-Oy4tmUrW.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-Oy4tmUrW.js.map} +1 -1
  42. package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-BBmhcWFV.mjs} +70 -37
  43. package/dist/_chunks/Relations-BBmhcWFV.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-eG-9p_qS.js} +69 -36
  45. package/dist/_chunks/Relations-eG-9p_qS.js.map +1 -0
  46. package/dist/_chunks/{en-fbKQxLGn.js → en-Bm0D0IWz.js} +17 -15
  47. package/dist/_chunks/{en-fbKQxLGn.js.map → en-Bm0D0IWz.js.map} +1 -1
  48. package/dist/_chunks/{en-Ux26r5pl.mjs → en-DKV44jRb.mjs} +17 -15
  49. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-DKV44jRb.mjs.map} +1 -1
  50. package/dist/_chunks/{index-DVPWZkbS.js → index-BIWDoFLK.js} +1003 -669
  51. package/dist/_chunks/index-BIWDoFLK.js.map +1 -0
  52. package/dist/_chunks/{index-DJXJw9V5.mjs → index-BrUzbQ30.mjs} +1021 -688
  53. package/dist/_chunks/index-BrUzbQ30.mjs.map +1 -0
  54. package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-_5-cXs34.mjs} +25 -12
  55. package/dist/_chunks/layout-_5-cXs34.mjs.map +1 -0
  56. package/dist/_chunks/{layout-Dm6fbiQj.js → layout-lMc9i1-Z.js} +24 -11
  57. package/dist/_chunks/layout-lMc9i1-Z.js.map +1 -0
  58. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  59. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  60. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  61. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  62. package/dist/_chunks/{relations-CKnpRgrN.js → relations-BRHithi8.js} +3 -7
  63. package/dist/_chunks/relations-BRHithi8.js.map +1 -0
  64. package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-B_VLk-DD.mjs} +3 -7
  65. package/dist/_chunks/relations-B_VLk-DD.mjs.map +1 -0
  66. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  67. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  68. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  69. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  70. package/dist/admin/index.js +2 -1
  71. package/dist/admin/index.js.map +1 -1
  72. package/dist/admin/index.mjs +5 -4
  73. package/dist/admin/src/exports.d.ts +1 -1
  74. package/dist/admin/src/history/index.d.ts +3 -0
  75. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  76. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  77. package/dist/admin/src/index.d.ts +1 -0
  78. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  79. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  80. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  81. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  82. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  83. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  84. package/dist/admin/src/preview/constants.d.ts +1 -0
  85. package/dist/admin/src/preview/index.d.ts +4 -0
  86. package/dist/admin/src/services/api.d.ts +1 -1
  87. package/dist/admin/src/services/components.d.ts +2 -2
  88. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  89. package/dist/admin/src/services/documents.d.ts +19 -17
  90. package/dist/admin/src/services/init.d.ts +1 -1
  91. package/dist/admin/src/services/relations.d.ts +2 -2
  92. package/dist/admin/src/services/uid.d.ts +3 -3
  93. package/dist/admin/src/utils/validation.d.ts +4 -1
  94. package/dist/server/index.js +321 -148
  95. package/dist/server/index.js.map +1 -1
  96. package/dist/server/index.mjs +322 -149
  97. package/dist/server/index.mjs.map +1 -1
  98. package/dist/server/src/bootstrap.d.ts.map +1 -1
  99. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  100. package/dist/server/src/controllers/index.d.ts.map +1 -1
  101. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  102. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  103. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  104. package/dist/server/src/controllers/utils/metadata.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 +4 -4
  110. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  111. package/dist/server/src/index.d.ts +4 -4
  112. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  113. package/dist/server/src/preview/constants.d.ts +2 -0
  114. package/dist/server/src/preview/constants.d.ts.map +1 -0
  115. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  116. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  117. package/dist/server/src/preview/controllers/preview.d.ts +9 -0
  118. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  119. package/dist/server/src/preview/index.d.ts +4 -0
  120. package/dist/server/src/preview/index.d.ts.map +1 -0
  121. package/dist/server/src/preview/routes/index.d.ts +8 -0
  122. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  123. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  124. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  125. package/dist/server/src/preview/services/index.d.ts +4 -0
  126. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  127. package/dist/server/src/preview/services/preview.d.ts +6 -0
  128. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  129. package/dist/server/src/preview/utils.d.ts +7 -0
  130. package/dist/server/src/preview/utils.d.ts.map +1 -0
  131. package/dist/server/src/routes/index.d.ts.map +1 -1
  132. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  133. package/dist/server/src/services/document-metadata.d.ts +8 -8
  134. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  135. package/dist/server/src/services/index.d.ts +4 -4
  136. package/dist/server/src/services/index.d.ts.map +1 -1
  137. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  138. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  139. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  140. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  141. package/dist/server/src/utils/index.d.ts +2 -0
  142. package/dist/server/src/utils/index.d.ts.map +1 -1
  143. package/dist/shared/contracts/collection-types.d.ts +3 -1
  144. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  145. package/package.json +12 -12
  146. package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
  147. package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
  148. package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
  149. package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
  150. package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
  151. package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
  152. package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
  153. package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
  154. package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
  155. package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
  156. package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
  157. package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
  158. package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
  159. package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
  160. package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
  161. package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
  162. package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
  163. package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
  164. package/dist/_chunks/relations-BH_kBSJ0.mjs.map +0 -1
  165. package/dist/_chunks/relations-CKnpRgrN.js.map +0 -1
  166. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  167. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  168. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  169. package/strapi-server.js +0 -3
@@ -121,7 +121,7 @@ const createHistoryVersionController = ({ strapi: strapi2 }) => {
121
121
  }
122
122
  };
123
123
  };
124
- const controllers$1 = {
124
+ const controllers$2 = {
125
125
  "history-version": createHistoryVersionController
126
126
  /**
127
127
  * Casting is needed because the types aren't aware that Strapi supports
@@ -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,6 +509,42 @@ 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,
@@ -502,63 +557,45 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
502
557
  return;
503
558
  }
504
559
  strapi2.documents.use(async (context, next) => {
505
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
506
- return next();
507
- }
508
- if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
509
- return next();
510
- }
511
- if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
512
- return next();
513
- }
514
- const contentTypeUid = context.contentType.uid;
515
- if (!contentTypeUid.startsWith("api::")) {
516
- return next();
517
- }
518
560
  const result = await next();
519
- const documentContext = {
520
- documentId: context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId,
521
- locale: context.params?.locale
522
- };
561
+ if (!shouldCreateHistoryVersion(context)) {
562
+ return result;
563
+ }
564
+ const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
523
565
  const defaultLocale = await serviceUtils.getDefaultLocale();
524
- const locale = documentContext.locale || defaultLocale;
525
- if (Array.isArray(locale)) {
526
- strapi2.log.warn(
527
- "[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
528
- );
529
- return next();
566
+ const locales = fp.castArray(context.params?.locale || defaultLocale);
567
+ if (!locales.length) {
568
+ return result;
530
569
  }
531
- const document = await strapi2.documents(contentTypeUid).findOne({
532
- documentId: documentContext.documentId,
533
- locale,
534
- 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
+ )
535
585
  });
536
- const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
537
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
538
- const componentsSchemas = Object.keys(
539
- attributesSchema
540
- ).reduce((currentComponentSchemas, key) => {
541
- const fieldSchema = attributesSchema[key];
542
- if (fieldSchema.type === "component") {
543
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
544
- return {
545
- ...currentComponentSchemas,
546
- [fieldSchema.component]: componentSchema
547
- };
548
- }
549
- return currentComponentSchemas;
550
- }, {});
551
586
  await strapi2.db.transaction(async ({ onCommit }) => {
552
- onCommit(() => {
553
- getService(strapi2, "history").createVersion({
554
- contentType: contentTypeUid,
555
- data: fp.omit(FIELDS_TO_IGNORE, document),
556
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
557
- componentsSchemas,
558
- relatedDocumentId: documentContext.documentId,
559
- locale,
560
- status
561
- });
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
+ }
562
599
  });
563
600
  });
564
601
  return result;
@@ -583,17 +620,17 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
583
620
  }
584
621
  };
585
622
  };
586
- const services$1 = {
623
+ const services$2 = {
587
624
  history: createHistoryService,
588
625
  lifecycles: createLifecyclesService
589
626
  };
590
- const info = { pluginName: "content-manager", type: "admin" };
627
+ const info$1 = { pluginName: "content-manager", type: "admin" };
591
628
  const historyVersionRouter = {
592
629
  type: "admin",
593
630
  routes: [
594
631
  {
595
632
  method: "GET",
596
- info,
633
+ info: info$1,
597
634
  path: "/history-versions",
598
635
  handler: "history-version.findMany",
599
636
  config: {
@@ -602,7 +639,7 @@ const historyVersionRouter = {
602
639
  },
603
640
  {
604
641
  method: "PUT",
605
- info,
642
+ info: info$1,
606
643
  path: "/history-versions/:versionId/restore",
607
644
  handler: "history-version.restoreVersion",
608
645
  config: {
@@ -611,7 +648,7 @@ const historyVersionRouter = {
611
648
  }
612
649
  ]
613
650
  };
614
- const routes$1 = {
651
+ const routes$2 = {
615
652
  "history-version": historyVersionRouter
616
653
  };
617
654
  const historyVersion = {
@@ -658,7 +695,7 @@ const historyVersion = {
658
695
  }
659
696
  }
660
697
  };
661
- const getFeature = () => {
698
+ const getFeature$1 = () => {
662
699
  if (strapi.ee.features.isEnabled("cms-content-history")) {
663
700
  return {
664
701
  register({ strapi: strapi2 }) {
@@ -670,9 +707,9 @@ const getFeature = () => {
670
707
  destroy({ strapi: strapi2 }) {
671
708
  getService(strapi2, "lifecycles").destroy();
672
709
  },
673
- controllers: controllers$1,
674
- services: services$1,
675
- routes: routes$1
710
+ controllers: controllers$2,
711
+ services: services$2,
712
+ routes: routes$2
676
713
  };
677
714
  }
678
715
  return {
@@ -681,7 +718,7 @@ const getFeature = () => {
681
718
  }
682
719
  };
683
720
  };
684
- const history = getFeature();
721
+ const history = getFeature$1();
685
722
  const register = async ({ strapi: strapi2 }) => {
686
723
  await history.register?.({ strapi: strapi2 });
687
724
  };
@@ -689,6 +726,62 @@ const ALLOWED_WEBHOOK_EVENTS = {
689
726
  ENTRY_PUBLISH: "entry.publish",
690
727
  ENTRY_UNPUBLISH: "entry.unpublish"
691
728
  };
729
+ const FEATURE_ID = "preview";
730
+ const info = { pluginName: "content-manager", type: "admin" };
731
+ const previewRouter = {
732
+ type: "admin",
733
+ routes: [
734
+ {
735
+ method: "GET",
736
+ info,
737
+ path: "/preview/url/:contentType",
738
+ handler: "preview.getPreviewURL",
739
+ config: {
740
+ policies: ["admin::isAuthenticatedAdmin"]
741
+ }
742
+ }
743
+ ]
744
+ };
745
+ const routes$1 = {
746
+ preview: previewRouter
747
+ };
748
+ const createPreviewController = () => {
749
+ return {
750
+ async getPreviewURL(ctx) {
751
+ ctx.request;
752
+ return {
753
+ data: { url: "" }
754
+ };
755
+ }
756
+ };
757
+ };
758
+ const controllers$1 = {
759
+ preview: createPreviewController
760
+ /**
761
+ * Casting is needed because the types aren't aware that Strapi supports
762
+ * passing a controller factory as the value, instead of a controller object directly
763
+ */
764
+ };
765
+ const createPreviewService = () => {
766
+ };
767
+ const services$1 = {
768
+ preview: createPreviewService
769
+ };
770
+ const getFeature = () => {
771
+ if (!strapi.features.future.isEnabled(FEATURE_ID)) {
772
+ return {};
773
+ }
774
+ return {
775
+ bootstrap() {
776
+ console.log("Bootstrapping preview server");
777
+ strapi.config.get("admin.preview");
778
+ },
779
+ routes: routes$1,
780
+ controllers: controllers$1,
781
+ services: services$1
782
+ };
783
+ };
784
+ const preview = getFeature();
692
785
  const bootstrap = async () => {
693
786
  Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
694
787
  strapi.get("webhookStore").addAllowedEvent(key, value);
@@ -698,6 +791,7 @@ const bootstrap = async () => {
698
791
  await getService$1("content-types").syncConfigurations();
699
792
  await getService$1("permission").registerPermissions();
700
793
  await history.bootstrap?.({ strapi });
794
+ await preview.bootstrap?.({ strapi });
701
795
  };
702
796
  const destroy = async ({ strapi: strapi2 }) => {
703
797
  await history.destroy?.({ strapi: strapi2 });
@@ -1187,7 +1281,8 @@ const admin = {
1187
1281
  };
1188
1282
  const routes = {
1189
1283
  admin,
1190
- ...history.routes ? history.routes : {}
1284
+ ...history.routes ? history.routes : {},
1285
+ ...preview.routes ? preview.routes : {}
1191
1286
  };
1192
1287
  const hasPermissionsSchema = strapiUtils.yup.object({
1193
1288
  actions: strapiUtils.yup.array().of(strapiUtils.yup.string()),
@@ -1198,6 +1293,11 @@ const { createPolicy } = strapiUtils.policy;
1198
1293
  const hasPermissions = createPolicy({
1199
1294
  name: "plugin::content-manager.hasPermissions",
1200
1295
  validator: validateHasPermissionsInput,
1296
+ /**
1297
+ * NOTE: Action aliases are currently not checked at this level (policy).
1298
+ * This is currently the intended behavior to avoid changing the behavior of API related permissions.
1299
+ * If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
1300
+ */
1201
1301
  handler(ctx, config = {}) {
1202
1302
  const { actions = [], hasAtLeastOne = false } = config;
1203
1303
  const { userAbility } = ctx.state;
@@ -1591,9 +1691,11 @@ const multipleLocaleSchema = strapiUtils.yup.lazy(
1591
1691
  (value) => Array.isArray(value) ? strapiUtils.yup.array().of(singleLocaleSchema.required()) : singleLocaleSchema
1592
1692
  );
1593
1693
  const statusSchema = strapiUtils.yup.mixed().oneOf(["draft", "published"], "Invalid status");
1594
- const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
1694
+ const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
1595
1695
  const { allowMultipleLocales } = opts;
1596
- const { locale, status, ...rest } = request || {};
1696
+ const { locale, status: providedStatus, ...rest } = request || {};
1697
+ const defaultStatus = strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
1698
+ const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
1597
1699
  const schema = strapiUtils.yup.object().shape({
1598
1700
  locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
1599
1701
  status: statusSchema
@@ -1641,7 +1743,7 @@ const createDocument = async (ctx, opts) => {
1641
1743
  const setCreator = strapiUtils.setCreatorFields({ user });
1642
1744
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1643
1745
  const sanitizedBody = await sanitizeFn(body);
1644
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(body);
1746
+ const { locale, status } = await getDocumentLocaleAndStatus(body, model);
1645
1747
  return documentManager2.create(model, {
1646
1748
  data: sanitizedBody,
1647
1749
  locale,
@@ -1660,7 +1762,7 @@ const updateDocument = async (ctx, opts) => {
1660
1762
  }
1661
1763
  const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
1662
1764
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1663
- const { locale } = await getDocumentLocaleAndStatus(body);
1765
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1664
1766
  const [documentVersion, documentExists] = await Promise.all([
1665
1767
  documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
1666
1768
  documentManager2.exists(model, id)
@@ -1676,7 +1778,7 @@ const updateDocument = async (ctx, opts) => {
1676
1778
  throw new strapiUtils.errors.ForbiddenError();
1677
1779
  }
1678
1780
  const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
1679
- const setCreator = strapiUtils.setCreatorFields({ user, isEdition: true });
1781
+ const setCreator = documentVersion ? strapiUtils.setCreatorFields({ user, isEdition: true }) : strapiUtils.setCreatorFields({ user });
1680
1782
  const sanitizeFn = strapiUtils.async.pipe(pickPermittedFields, setCreator);
1681
1783
  const sanitizedBody = await sanitizeFn(body);
1682
1784
  return documentManager2.update(documentVersion?.documentId || id, model, {
@@ -1698,7 +1800,7 @@ const collectionTypes = {
1698
1800
  }
1699
1801
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
1700
1802
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
1701
- const { locale, status } = await getDocumentLocaleAndStatus(query);
1803
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
1702
1804
  const { results: documents, pagination } = await documentManager2.findPage(
1703
1805
  { ...permissionQuery, populate, locale, status },
1704
1806
  model
@@ -1733,7 +1835,7 @@ const collectionTypes = {
1733
1835
  }
1734
1836
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
1735
1837
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1736
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
1838
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
1737
1839
  const version = await documentManager2.findOne(id, model, {
1738
1840
  populate,
1739
1841
  locale,
@@ -1748,7 +1850,7 @@ const collectionTypes = {
1748
1850
  permissionChecker2,
1749
1851
  model,
1750
1852
  // @ts-expect-error TODO: fix
1751
- { id, locale, publishedAt: null },
1853
+ { documentId: id, locale, publishedAt: null },
1752
1854
  { availableLocales: true, availableStatus: false }
1753
1855
  );
1754
1856
  ctx.body = { data: {}, meta };
@@ -1800,7 +1902,7 @@ const collectionTypes = {
1800
1902
  }
1801
1903
  const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
1802
1904
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1803
- const { locale } = await getDocumentLocaleAndStatus(body);
1905
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1804
1906
  const document = await documentManager2.findOne(id, model, {
1805
1907
  populate,
1806
1908
  locale,
@@ -1845,7 +1947,7 @@ const collectionTypes = {
1845
1947
  }
1846
1948
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
1847
1949
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1848
- const { locale } = await getDocumentLocaleAndStatus(ctx.query);
1950
+ const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
1849
1951
  const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
1850
1952
  if (documentLocales.length === 0) {
1851
1953
  return ctx.notFound();
@@ -1874,11 +1976,34 @@ const collectionTypes = {
1874
1976
  const publishedDocument = await strapi.db.transaction(async () => {
1875
1977
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1876
1978
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1877
- const document = id ? await updateDocument(ctx, { populate }) : await createDocument(ctx, { populate });
1979
+ let document;
1980
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1981
+ const isCreate = fp.isNil(id);
1982
+ if (isCreate) {
1983
+ if (permissionChecker2.cannot.create()) {
1984
+ throw new strapiUtils.errors.ForbiddenError();
1985
+ }
1986
+ document = await createDocument(ctx, { populate });
1987
+ }
1988
+ const isUpdate = !isCreate;
1989
+ if (isUpdate) {
1990
+ const documentExists = documentManager2.exists(model, id);
1991
+ if (!documentExists) {
1992
+ throw new strapiUtils.errors.NotFoundError("Document not found");
1993
+ }
1994
+ document = await documentManager2.findOne(id, model, { populate, locale });
1995
+ if (!document) {
1996
+ if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
1997
+ throw new strapiUtils.errors.ForbiddenError();
1998
+ }
1999
+ document = await updateDocument(ctx);
2000
+ } else if (permissionChecker2.can.update(document)) {
2001
+ await updateDocument(ctx);
2002
+ }
2003
+ }
1878
2004
  if (permissionChecker2.cannot.publish(document)) {
1879
2005
  throw new strapiUtils.errors.ForbiddenError();
1880
2006
  }
1881
- const { locale } = await getDocumentLocaleAndStatus(body);
1882
2007
  const publishResult = await documentManager2.publish(document.documentId, model, {
1883
2008
  locale
1884
2009
  // TODO: Allow setting creator fields on publish
@@ -1905,7 +2030,9 @@ const collectionTypes = {
1905
2030
  }
1906
2031
  const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
1907
2032
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
1908
- const { locale } = await getDocumentLocaleAndStatus(body, { allowMultipleLocales: true });
2033
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2034
+ allowMultipleLocales: true
2035
+ });
1909
2036
  const entityPromises = documentIds.map(
1910
2037
  (documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
1911
2038
  );
@@ -1932,7 +2059,9 @@ const collectionTypes = {
1932
2059
  if (permissionChecker2.cannot.unpublish()) {
1933
2060
  return ctx.forbidden();
1934
2061
  }
1935
- const { locale } = await getDocumentLocaleAndStatus(body);
2062
+ const { locale } = await getDocumentLocaleAndStatus(body, model, {
2063
+ allowMultipleLocales: true
2064
+ });
1936
2065
  const entityPromises = documentIds.map(
1937
2066
  (documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
1938
2067
  );
@@ -1965,7 +2094,7 @@ const collectionTypes = {
1965
2094
  }
1966
2095
  const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
1967
2096
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
1968
- const { locale } = await getDocumentLocaleAndStatus(body);
2097
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
1969
2098
  const document = await documentManager2.findOne(id, model, {
1970
2099
  populate,
1971
2100
  locale,
@@ -2002,7 +2131,7 @@ const collectionTypes = {
2002
2131
  }
2003
2132
  const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
2004
2133
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2005
- const { locale } = await getDocumentLocaleAndStatus(body);
2134
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2006
2135
  const document = await documentManager2.findOne(id, model, {
2007
2136
  populate,
2008
2137
  locale,
@@ -2033,7 +2162,7 @@ const collectionTypes = {
2033
2162
  }
2034
2163
  const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
2035
2164
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2036
- const { locale } = await getDocumentLocaleAndStatus(body);
2165
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2037
2166
  const documentLocales = await documentManager2.findLocales(documentIds, model, {
2038
2167
  populate,
2039
2168
  locale
@@ -2060,7 +2189,7 @@ const collectionTypes = {
2060
2189
  }
2061
2190
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
2062
2191
  const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
2063
- const { locale, status = "draft" } = await getDocumentLocaleAndStatus(ctx.query);
2192
+ const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
2064
2193
  const entity = await documentManager2.findOne(id, model, { populate, locale, status });
2065
2194
  if (!entity) {
2066
2195
  return ctx.notFound();
@@ -2083,7 +2212,7 @@ const collectionTypes = {
2083
2212
  if (permissionChecker2.cannot.read()) {
2084
2213
  return ctx.forbidden();
2085
2214
  }
2086
- const entities = await documentManager2.findMany(
2215
+ const documents = await documentManager2.findMany(
2087
2216
  {
2088
2217
  filters: {
2089
2218
  documentId: ids
@@ -2092,7 +2221,7 @@ const collectionTypes = {
2092
2221
  },
2093
2222
  model
2094
2223
  );
2095
- if (!entities) {
2224
+ if (!documents) {
2096
2225
  return ctx.notFound();
2097
2226
  }
2098
2227
  const number = await documentManager2.countManyEntriesDraftRelations(ids, model, locale);
@@ -2283,32 +2412,37 @@ const sanitizeMainField = (model, mainField, userAbility) => {
2283
2412
  userAbility,
2284
2413
  model: model.uid
2285
2414
  });
2286
- if (!isListable(model, mainField)) {
2415
+ const isMainFieldListable = isListable(model, mainField);
2416
+ const canReadMainField = permissionChecker2.can.read(null, mainField);
2417
+ if (!isMainFieldListable || !canReadMainField) {
2287
2418
  return "id";
2288
2419
  }
2289
- if (permissionChecker2.cannot.read(null, mainField)) {
2290
- if (model.uid === "plugin::users-permissions.role") {
2291
- const userPermissionChecker = getService$1("permission-checker").create({
2292
- userAbility,
2293
- model: "plugin::users-permissions.user"
2294
- });
2295
- if (userPermissionChecker.can.read()) {
2296
- return "name";
2297
- }
2298
- }
2299
- return "id";
2420
+ if (model.uid === "plugin::users-permissions.role") {
2421
+ return "name";
2300
2422
  }
2301
2423
  return mainField;
2302
2424
  };
2303
- const addStatusToRelations = async (uid2, relations2) => {
2304
- if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentTypes[uid2])) {
2425
+ const addStatusToRelations = async (targetUid, relations2) => {
2426
+ if (!strapiUtils.contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
2305
2427
  return relations2;
2306
2428
  }
2307
2429
  const documentMetadata2 = getService$1("document-metadata");
2308
- const documentsAvailableStatus = await documentMetadata2.getManyAvailableStatus(uid2, relations2);
2430
+ if (!relations2.length) {
2431
+ return relations2;
2432
+ }
2433
+ const firstRelation = relations2[0];
2434
+ const filters = {
2435
+ documentId: { $in: relations2.map((r) => r.documentId) },
2436
+ // NOTE: find the "opposite" status
2437
+ publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
2438
+ };
2439
+ const availableStatus = await strapi.query(targetUid).findMany({
2440
+ select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
2441
+ filters
2442
+ });
2309
2443
  return relations2.map((relation) => {
2310
- const availableStatuses = documentsAvailableStatus.filter(
2311
- (availableDocument) => availableDocument.documentId === relation.documentId
2444
+ const availableStatuses = availableStatus.filter(
2445
+ (availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
2312
2446
  );
2313
2447
  return {
2314
2448
  ...relation,
@@ -2329,11 +2463,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
2329
2463
  const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
2330
2464
  const isSourceLocalized = isLocalized(sourceModel);
2331
2465
  const isTargetLocalized = isLocalized(targetModel);
2332
- let validatedLocale = locale;
2333
- if (!targetModel || !isTargetLocalized)
2334
- validatedLocale = void 0;
2335
2466
  return {
2336
- locale: validatedLocale,
2467
+ locale,
2337
2468
  isSourceLocalized,
2338
2469
  isTargetLocalized
2339
2470
  };
@@ -2436,7 +2567,7 @@ const relations = {
2436
2567
  attribute,
2437
2568
  fieldsToSelect,
2438
2569
  mainField,
2439
- source: { schema: sourceSchema },
2570
+ source: { schema: sourceSchema, isLocalized: isSourceLocalized },
2440
2571
  target: { schema: targetSchema, isLocalized: isTargetLocalized },
2441
2572
  sourceSchema,
2442
2573
  targetSchema,
@@ -2458,7 +2589,8 @@ const relations = {
2458
2589
  fieldsToSelect,
2459
2590
  mainField,
2460
2591
  source: {
2461
- schema: { uid: sourceUid, modelType: sourceModelType }
2592
+ schema: { uid: sourceUid, modelType: sourceModelType },
2593
+ isLocalized: isSourceLocalized
2462
2594
  },
2463
2595
  target: {
2464
2596
  schema: { uid: targetUid },
@@ -2496,12 +2628,16 @@ const relations = {
2496
2628
  } else {
2497
2629
  where.id = id;
2498
2630
  }
2499
- if (status) {
2500
- where[`${alias}.published_at`] = getPublishedAtClause(status, targetUid);
2631
+ const publishedAt = getPublishedAtClause(status, targetUid);
2632
+ if (!fp.isEmpty(publishedAt)) {
2633
+ where[`${alias}.published_at`] = publishedAt;
2501
2634
  }
2502
- if (filterByLocale) {
2635
+ if (isTargetLocalized && locale) {
2503
2636
  where[`${alias}.locale`] = locale;
2504
2637
  }
2638
+ if (isSourceLocalized && locale) {
2639
+ where.locale = locale;
2640
+ }
2505
2641
  if ((idsToInclude?.length ?? 0) !== 0) {
2506
2642
  where[`${alias}.id`].$notIn = idsToInclude;
2507
2643
  }
@@ -2519,7 +2655,8 @@ const relations = {
2519
2655
  id: { $notIn: fp.uniq(idsToOmit) }
2520
2656
  });
2521
2657
  }
2522
- const res = await strapi.db.query(targetUid).findPage(strapi.get("query-params").transform(targetUid, queryParams));
2658
+ const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
2659
+ const res = await strapi.db.query(targetUid).findPage(dbQuery);
2523
2660
  ctx.body = {
2524
2661
  ...res,
2525
2662
  results: await addStatusToRelations(targetUid, res.results)
@@ -2534,29 +2671,39 @@ const relations = {
2534
2671
  attribute,
2535
2672
  targetField,
2536
2673
  fieldsToSelect,
2537
- source: {
2538
- schema: { uid: sourceUid }
2539
- },
2540
- target: {
2541
- schema: { uid: targetUid }
2542
- }
2674
+ status,
2675
+ source: { schema: sourceSchema },
2676
+ target: { schema: targetSchema }
2543
2677
  } = await this.extractAndValidateRequestInfo(ctx, id);
2678
+ const { uid: sourceUid } = sourceSchema;
2679
+ const { uid: targetUid } = targetSchema;
2544
2680
  const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
2545
2681
  const dbQuery = strapi.db.query(sourceUid);
2546
2682
  const loadRelations = strapiUtils.relations.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
2683
+ const filters = {};
2684
+ if (sourceSchema?.options?.draftAndPublish) {
2685
+ if (targetSchema?.options?.draftAndPublish) {
2686
+ if (status === "published") {
2687
+ filters.publishedAt = { $notNull: true };
2688
+ } else {
2689
+ filters.publishedAt = { $null: true };
2690
+ }
2691
+ }
2692
+ } else if (targetSchema?.options?.draftAndPublish) {
2693
+ filters.publishedAt = { $null: true };
2694
+ }
2547
2695
  const res = await loadRelations({ id: entryId }, targetField, {
2548
- select: ["id", "documentId", "locale", "publishedAt"],
2696
+ select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
2549
2697
  ordering: "desc",
2550
2698
  page: ctx.request.query.page,
2551
- pageSize: ctx.request.query.pageSize
2699
+ pageSize: ctx.request.query.pageSize,
2700
+ filters
2552
2701
  });
2553
2702
  const loadedIds = res.results.map((item) => item.id);
2554
2703
  addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
2555
2704
  const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
2556
2705
  ...strapi.get("query-params").transform(targetUid, permissionQuery),
2557
- ordering: "desc",
2558
- page: ctx.request.query.page,
2559
- pageSize: ctx.request.query.pageSize
2706
+ ordering: "desc"
2560
2707
  });
2561
2708
  const relationsUnion = fp.uniqBy("id", fp.concat(sanitizedRes.results, res.results));
2562
2709
  ctx.body = {
@@ -2588,7 +2735,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
2588
2735
  throw new strapiUtils.errors.ForbiddenError();
2589
2736
  }
2590
2737
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
2591
- const { locale } = await getDocumentLocaleAndStatus(body);
2738
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2592
2739
  const [documentVersion, otherDocumentVersion] = await Promise.all([
2593
2740
  findDocument(sanitizedQuery, model, { locale, status: "draft" }),
2594
2741
  // Find the first document to check if it exists
@@ -2629,7 +2776,7 @@ const singleTypes = {
2629
2776
  return ctx.forbidden();
2630
2777
  }
2631
2778
  const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
2632
- const { locale, status } = await getDocumentLocaleAndStatus(query);
2779
+ const { locale, status } = await getDocumentLocaleAndStatus(query, model);
2633
2780
  const version = await findDocument(permissionQuery, model, { locale, status });
2634
2781
  if (!version) {
2635
2782
  if (permissionChecker2.cannot.create()) {
@@ -2643,7 +2790,7 @@ const singleTypes = {
2643
2790
  permissionChecker2,
2644
2791
  model,
2645
2792
  // @ts-expect-error - fix types
2646
- { id: document.documentId, locale, publishedAt: null },
2793
+ { documentId: document.documentId, locale, publishedAt: null },
2647
2794
  { availableLocales: true, availableStatus: false }
2648
2795
  );
2649
2796
  ctx.body = { data: {}, meta };
@@ -2674,7 +2821,7 @@ const singleTypes = {
2674
2821
  }
2675
2822
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
2676
2823
  const populate = await buildPopulateFromQuery(sanitizedQuery, model);
2677
- const { locale } = await getDocumentLocaleAndStatus(query);
2824
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2678
2825
  const documentLocales = await documentManager2.findLocales(void 0, model, {
2679
2826
  populate,
2680
2827
  locale
@@ -2711,7 +2858,7 @@ const singleTypes = {
2711
2858
  if (permissionChecker2.cannot.publish(document)) {
2712
2859
  throw new strapiUtils.errors.ForbiddenError();
2713
2860
  }
2714
- const { locale } = await getDocumentLocaleAndStatus(document);
2861
+ const { locale } = await getDocumentLocaleAndStatus(document, model);
2715
2862
  const publishResult = await documentManager2.publish(document.documentId, model, { locale });
2716
2863
  return publishResult.at(0);
2717
2864
  });
@@ -2734,7 +2881,7 @@ const singleTypes = {
2734
2881
  return ctx.forbidden();
2735
2882
  }
2736
2883
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
2737
- const { locale } = await getDocumentLocaleAndStatus(body);
2884
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2738
2885
  const document = await findDocument(sanitizedQuery, model, { locale });
2739
2886
  if (!document) {
2740
2887
  return ctx.notFound();
@@ -2766,7 +2913,7 @@ const singleTypes = {
2766
2913
  return ctx.forbidden();
2767
2914
  }
2768
2915
  const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
2769
- const { locale } = await getDocumentLocaleAndStatus(body);
2916
+ const { locale } = await getDocumentLocaleAndStatus(body, model);
2770
2917
  const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
2771
2918
  if (!document) {
2772
2919
  return ctx.notFound();
@@ -2786,7 +2933,7 @@ const singleTypes = {
2786
2933
  const { query } = ctx.request;
2787
2934
  const documentManager2 = getService$1("document-manager");
2788
2935
  const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
2789
- const { locale } = await getDocumentLocaleAndStatus(query);
2936
+ const { locale } = await getDocumentLocaleAndStatus(query, model);
2790
2937
  if (permissionChecker2.cannot.read()) {
2791
2938
  return ctx.forbidden();
2792
2939
  }
@@ -2807,7 +2954,7 @@ const uid$1 = {
2807
2954
  async generateUID(ctx) {
2808
2955
  const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
2809
2956
  const { query = {} } = ctx.request;
2810
- const { locale } = await getDocumentLocaleAndStatus(query);
2957
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2811
2958
  await validateUIDField(contentTypeUID, field);
2812
2959
  const uidService = getService$1("uid");
2813
2960
  ctx.body = {
@@ -2819,7 +2966,7 @@ const uid$1 = {
2819
2966
  ctx.request.body
2820
2967
  );
2821
2968
  const { query = {} } = ctx.request;
2822
- const { locale } = await getDocumentLocaleAndStatus(query);
2969
+ const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
2823
2970
  await validateUIDField(contentTypeUID, field);
2824
2971
  const uidService = getService$1("uid");
2825
2972
  const isAvailable = await uidService.checkUIDAvailability({
@@ -2842,7 +2989,8 @@ const controllers = {
2842
2989
  relations,
2843
2990
  "single-types": singleTypes,
2844
2991
  uid: uid$1,
2845
- ...history.controllers ? history.controllers : {}
2992
+ ...history.controllers ? history.controllers : {},
2993
+ ...preview.controllers ? preview.controllers : {}
2846
2994
  };
2847
2995
  const keys = {
2848
2996
  CONFIGURATION: "configuration"
@@ -3462,12 +3610,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
3462
3610
  ability: userAbility,
3463
3611
  model
3464
3612
  });
3465
- const toSubject = (entity) => entity ? permissionsManager.toSubject(entity, model) : model;
3613
+ const { actionProvider } = strapi2.service("admin::permission");
3614
+ const toSubject = (entity) => {
3615
+ return entity ? permissionsManager.toSubject(entity, model) : model;
3616
+ };
3466
3617
  const can = (action, entity, field) => {
3467
- return userAbility.can(action, toSubject(entity), field);
3618
+ const subject = toSubject(entity);
3619
+ const aliases = actionProvider.unstable_aliases(action, model);
3620
+ return (
3621
+ // Test the original action to see if it passes
3622
+ userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
3623
+ aliases.some((alias) => userAbility.can(alias, subject, field))
3624
+ );
3468
3625
  };
3469
3626
  const cannot = (action, entity, field) => {
3470
- return userAbility.cannot(action, toSubject(entity), field);
3627
+ const subject = toSubject(entity);
3628
+ const aliases = actionProvider.unstable_aliases(action, model);
3629
+ return (
3630
+ // Test both the original action
3631
+ userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
3632
+ aliases.every((alias) => userAbility.cannot(alias, subject, field))
3633
+ );
3471
3634
  };
3472
3635
  const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
3473
3636
  return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
@@ -3744,6 +3907,10 @@ const getDeepPopulateDraftCount = (uid2) => {
3744
3907
  const attribute = model.attributes[attributeName];
3745
3908
  switch (attribute.type) {
3746
3909
  case "relation": {
3910
+ const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
3911
+ if (isMorphRelation) {
3912
+ break;
3913
+ }
3747
3914
  if (isVisibleAttribute$1(model, attributeName)) {
3748
3915
  populateAcc[attributeName] = {
3749
3916
  count: true,
@@ -3995,7 +4162,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
3995
4162
  */
3996
4163
  async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
3997
4164
  const versionsByLocale = fp.groupBy("locale", allVersions);
3998
- delete versionsByLocale[version.locale];
4165
+ if (version.locale) {
4166
+ delete versionsByLocale[version.locale];
4167
+ }
3999
4168
  const model = strapi2.getModel(uid2);
4000
4169
  const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
4001
4170
  const traversalFunction = async (localeVersion) => strapiUtils.traverseEntity(
@@ -4121,7 +4290,13 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
4121
4290
  */
4122
4291
  async formatDocumentWithMetadata(uid2, document, opts = {}) {
4123
4292
  if (!document) {
4124
- return document;
4293
+ return {
4294
+ data: document,
4295
+ meta: {
4296
+ availableLocales: [],
4297
+ availableStatus: []
4298
+ }
4299
+ };
4125
4300
  }
4126
4301
  const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi2.getModel(uid2));
4127
4302
  if (!hasDraftAndPublish) {
@@ -4229,10 +4404,7 @@ const documentManager = ({ strapi: strapi2 }) => {
4229
4404
  async clone(id, body, uid2) {
4230
4405
  const populate = await buildDeepPopulate(uid2);
4231
4406
  const params = {
4232
- data: {
4233
- ...omitIdField(body),
4234
- [PUBLISHED_AT_ATTRIBUTE]: null
4235
- },
4407
+ data: omitIdField(body),
4236
4408
  populate
4237
4409
  };
4238
4410
  return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
@@ -4348,7 +4520,8 @@ const services = {
4348
4520
  permission,
4349
4521
  "populate-builder": populateBuilder$1,
4350
4522
  uid,
4351
- ...history.services ? history.services : {}
4523
+ ...history.services ? history.services : {},
4524
+ ...preview.services ? preview.services : {}
4352
4525
  };
4353
4526
  const index = () => {
4354
4527
  return {