@strapi/content-manager 0.0.0-experimental.a65a85fdea97faae8679d3ffc5f9d79af61abd26 → 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813

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 (83) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs → ComponentConfigurationPage-BPvzFjM7.mjs} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-BPvzFjM7.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-DjWJdz6Y.js} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-DjWJdz6Y.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs → EditConfigurationPage-DacbqQ_f.mjs} +3 -3
  6. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-DacbqQ_f.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js → EditConfigurationPage-Dmv83RlS.js} +3 -3
  8. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-Dmv83RlS.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs → EditViewPage-DDS6H9HO.mjs} +3 -3
  10. package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs.map → EditViewPage-DDS6H9HO.mjs.map} +1 -1
  11. package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-DvNpQkam.js} +3 -3
  12. package/dist/_chunks/{EditViewPage-CzOT5Kpj.js.map → EditViewPage-DvNpQkam.js.map} +1 -1
  13. package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-6gvGdPBV.mjs} +3 -3
  14. package/dist/_chunks/{Field-Dlh0uGnL.mjs.map → Field-6gvGdPBV.mjs.map} +1 -1
  15. package/dist/_chunks/{Field-Caef4JjM.js → Field-DmVKIAOo.js} +3 -3
  16. package/dist/_chunks/{Field-Caef4JjM.js.map → Field-DmVKIAOo.js.map} +1 -1
  17. package/dist/_chunks/{Form-BzuAjtRq.js → Form-CPZC9vWa.js} +5 -5
  18. package/dist/_chunks/{Form-BzuAjtRq.js.map → Form-CPZC9vWa.js.map} +1 -1
  19. package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-DW6K1IH-.mjs} +7 -7
  20. package/dist/_chunks/{Form-EnaQL_6L.mjs.map → Form-DW6K1IH-.mjs.map} +1 -1
  21. package/dist/_chunks/{History-C17LiyRg.js → History-DeAPlvtv.js} +6 -6
  22. package/dist/_chunks/History-DeAPlvtv.js.map +1 -0
  23. package/dist/_chunks/{History-D6sbCJvo.mjs → History-Dmr9fmUA.mjs} +8 -8
  24. package/dist/_chunks/History-Dmr9fmUA.mjs.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-DPCwW5Vr.js} +5 -5
  26. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-DhwvYcNv.mjs} +7 -7
  28. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +1 -0
  29. package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-5ySZ-VUs.js} +6 -6
  30. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +1 -0
  31. package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-BtAwuYLE.mjs} +8 -8
  32. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-DOC_yWOf.js} +4 -4
  34. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +1 -0
  35. package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-DSPxnxxp.mjs} +6 -6
  36. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +1 -0
  37. package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-Dwu8rRJu.js} +4 -5
  38. package/dist/_chunks/NoPermissionsPage-Dwu8rRJu.js.map +1 -0
  39. package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-UWDC-1Tw.mjs} +5 -6
  40. package/dist/_chunks/NoPermissionsPage-UWDC-1Tw.mjs.map +1 -0
  41. package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-CgWtgnPe.js} +3 -3
  42. package/dist/_chunks/{Relations-Czs-uZ-s.js.map → Relations-CgWtgnPe.js.map} +1 -1
  43. package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-J8cscLlR.mjs} +3 -3
  44. package/dist/_chunks/{Relations-CY7AtkDA.mjs.map → Relations-J8cscLlR.mjs.map} +1 -1
  45. package/dist/_chunks/{index-X_2tafck.js → index-C6AH2hEl.js} +10 -10
  46. package/dist/_chunks/{index-X_2tafck.js.map → index-C6AH2hEl.js.map} +1 -1
  47. package/dist/_chunks/{index-DNVx8ssZ.mjs → index-CwRRo1V9.mjs} +10 -10
  48. package/dist/_chunks/{index-DNVx8ssZ.mjs.map → index-CwRRo1V9.mjs.map} +1 -1
  49. package/dist/_chunks/{layout-dBc7wN7L.js → layout-B_SXLhqf.js} +5 -5
  50. package/dist/_chunks/{layout-dBc7wN7L.js.map → layout-B_SXLhqf.js.map} +1 -1
  51. package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-jIDzX0Fp.mjs} +6 -6
  52. package/dist/_chunks/{layout-Dnh0PNp9.mjs.map → layout-jIDzX0Fp.mjs.map} +1 -1
  53. package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-CuvIgCqI.mjs} +2 -2
  54. package/dist/_chunks/{relations-Dx7tMKJN.mjs.map → relations-CuvIgCqI.mjs.map} +1 -1
  55. package/dist/_chunks/{relations-4pHtBrHJ.js → relations-iBMa_OFG.js} +2 -2
  56. package/dist/_chunks/{relations-4pHtBrHJ.js.map → relations-iBMa_OFG.js.map} +1 -1
  57. package/dist/admin/index.js +1 -1
  58. package/dist/admin/index.mjs +1 -1
  59. package/dist/server/index.js +256 -211
  60. package/dist/server/index.js.map +1 -1
  61. package/dist/server/index.mjs +256 -211
  62. package/dist/server/index.mjs.map +1 -1
  63. package/dist/server/src/history/services/history.d.ts +2 -4
  64. package/dist/server/src/history/services/history.d.ts.map +1 -1
  65. package/dist/server/src/history/services/index.d.ts +6 -2
  66. package/dist/server/src/history/services/index.d.ts.map +1 -1
  67. package/dist/server/src/history/services/lifecycles.d.ts +9 -0
  68. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -0
  69. package/dist/server/src/history/services/utils.d.ts +41 -9
  70. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  71. package/dist/server/src/history/utils.d.ts +6 -2
  72. package/dist/server/src/history/utils.d.ts.map +1 -1
  73. package/package.json +6 -6
  74. package/dist/_chunks/History-C17LiyRg.js.map +0 -1
  75. package/dist/_chunks/History-D6sbCJvo.mjs.map +0 -1
  76. package/dist/_chunks/ListConfigurationPage-Ce4qs7qE.mjs.map +0 -1
  77. package/dist/_chunks/ListConfigurationPage-Dks5SX6f.js.map +0 -1
  78. package/dist/_chunks/ListViewPage-Be7S5aKL.mjs.map +0 -1
  79. package/dist/_chunks/ListViewPage-BwrZrPsh.js.map +0 -1
  80. package/dist/_chunks/NoContentTypePage-CIPmYQMm.mjs.map +0 -1
  81. package/dist/_chunks/NoContentTypePage-Cu5r1-JT.js.map +0 -1
  82. package/dist/_chunks/NoPermissionsPage-C-j6TEUF.js.map +0 -1
  83. package/dist/_chunks/NoPermissionsPage-DhJ7LYrr.mjs.map +0 -1
@@ -112,40 +112,65 @@ const FIELDS_TO_IGNORE = [
112
112
  "strapi_stage",
113
113
  "strapi_assignee"
114
114
  ];
115
- const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
116
- const sanitizedContentTypeSchemaAttributes = omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
117
- const reduceDifferenceToAttributesObject = (diffKeys, source) => {
118
- return diffKeys.reduce((previousAttributesObject, diffKey) => {
119
- previousAttributesObject[diffKey] = source[diffKey];
120
- return previousAttributesObject;
121
- }, {});
122
- };
123
- const versionSchemaKeys = Object.keys(versionSchemaAttributes);
124
- const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
125
- const uniqueToContentType = difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
126
- const added = reduceDifferenceToAttributesObject(
127
- uniqueToContentType,
128
- sanitizedContentTypeSchemaAttributes
129
- );
130
- const uniqueToVersion = difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
131
- const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
132
- return { added, removed };
133
- };
134
115
  const DEFAULT_RETENTION_DAYS = 90;
135
- const createHistoryService = ({ strapi: strapi2 }) => {
136
- const state = {
137
- deleteExpiredJob: null,
138
- isInitialized: false
116
+ const createServiceUtils = ({ strapi: strapi2 }) => {
117
+ const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
118
+ const sanitizedContentTypeSchemaAttributes = omit(
119
+ FIELDS_TO_IGNORE,
120
+ contentTypeSchemaAttributes
121
+ );
122
+ const reduceDifferenceToAttributesObject = (diffKeys, source) => {
123
+ return diffKeys.reduce(
124
+ (previousAttributesObject, diffKey) => {
125
+ previousAttributesObject[diffKey] = source[diffKey];
126
+ return previousAttributesObject;
127
+ },
128
+ {}
129
+ );
130
+ };
131
+ const versionSchemaKeys = Object.keys(versionSchemaAttributes);
132
+ const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
133
+ const uniqueToContentType = difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
134
+ const added = reduceDifferenceToAttributesObject(
135
+ uniqueToContentType,
136
+ sanitizedContentTypeSchemaAttributes
137
+ );
138
+ const uniqueToVersion = difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
139
+ const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
140
+ return { added, removed };
139
141
  };
140
- const query = strapi2.db.query(HISTORY_VERSION_UID);
141
- const getRetentionDays = (strapi22) => {
142
- const featureConfig = strapi22.ee.features.get("cms-content-history");
143
- const licenseRetentionDays = typeof featureConfig === "object" && featureConfig?.options.retentionDays;
144
- const userRetentionDays = strapi22.config.get("admin.history.retentionDays");
145
- if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
146
- return userRetentionDays;
142
+ const getRelationRestoreValue = async (versionRelationData, attribute) => {
143
+ if (Array.isArray(versionRelationData)) {
144
+ if (versionRelationData.length === 0)
145
+ return versionRelationData;
146
+ const existingAndMissingRelations = await Promise.all(
147
+ versionRelationData.map((relation) => {
148
+ return strapi2.documents(attribute.target).findOne({
149
+ documentId: relation.documentId,
150
+ locale: relation.locale || void 0
151
+ });
152
+ })
153
+ );
154
+ return existingAndMissingRelations.filter(
155
+ (relation) => relation !== null
156
+ );
147
157
  }
148
- return Math.min(licenseRetentionDays, DEFAULT_RETENTION_DAYS);
158
+ return strapi2.documents(attribute.target).findOne({
159
+ documentId: versionRelationData.documentId,
160
+ locale: versionRelationData.locale || void 0
161
+ });
162
+ };
163
+ const getMediaRestoreValue = async (versionRelationData, attribute) => {
164
+ if (attribute.multiple) {
165
+ const existingAndMissingMedias = await Promise.all(
166
+ // @ts-expect-error Fix the type definitions so this isn't any
167
+ versionRelationData.map((media) => {
168
+ return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
169
+ })
170
+ );
171
+ return existingAndMissingMedias.filter((media) => media != null);
172
+ }
173
+ return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
149
174
  };
150
175
  const localesService = strapi2.plugin("i18n")?.service("locales");
151
176
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
@@ -161,6 +186,15 @@ const createHistoryService = ({ strapi: strapi2 }) => {
161
186
  {}
162
187
  );
163
188
  };
189
+ const getRetentionDays = () => {
190
+ const featureConfig = strapi2.ee.features.get("cms-content-history");
191
+ const licenseRetentionDays = typeof featureConfig === "object" && featureConfig?.options.retentionDays;
192
+ const userRetentionDays = strapi2.config.get("admin.history.retentionDays");
193
+ if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
194
+ return userRetentionDays;
195
+ }
196
+ return Math.min(licenseRetentionDays, DEFAULT_RETENTION_DAYS);
197
+ };
164
198
  const getVersionStatus = async (contentTypeUid, document) => {
165
199
  const documentMetadataService = strapi2.plugin("content-manager").service("document-metadata");
166
200
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
@@ -202,80 +236,68 @@ const createHistoryService = ({ strapi: strapi2 }) => {
202
236
  return acc;
203
237
  }, {});
204
238
  };
205
- return {
206
- async bootstrap() {
207
- if (state.isInitialized) {
208
- return;
209
- }
210
- strapi2.documents.use(async (context, next) => {
211
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
212
- return next();
239
+ const buildMediaResponse = async (values) => {
240
+ return values.slice(0, 25).reduce(
241
+ async (currentRelationDataPromise, entry) => {
242
+ const currentRelationData = await currentRelationDataPromise;
243
+ if (!entry) {
244
+ return currentRelationData;
213
245
  }
214
- if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
215
- return next();
246
+ const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
247
+ if (relatedEntry) {
248
+ currentRelationData.results.push(relatedEntry);
249
+ } else {
250
+ currentRelationData.meta.missingCount += 1;
216
251
  }
217
- const contentTypeUid = context.contentType.uid;
218
- if (!contentTypeUid.startsWith("api::")) {
219
- return next();
252
+ return currentRelationData;
253
+ },
254
+ Promise.resolve({
255
+ results: [],
256
+ meta: { missingCount: 0 }
257
+ })
258
+ );
259
+ };
260
+ const buildRelationReponse = async (values, attributeSchema) => {
261
+ return values.slice(0, 25).reduce(
262
+ async (currentRelationDataPromise, entry) => {
263
+ const currentRelationData = await currentRelationDataPromise;
264
+ if (!entry) {
265
+ return currentRelationData;
220
266
  }
221
- const result = await next();
222
- const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
223
- const defaultLocale = await getDefaultLocale();
224
- const locale = documentContext.locale || defaultLocale;
225
- const document = await strapi2.documents(contentTypeUid).findOne({
226
- documentId: documentContext.documentId,
227
- locale,
228
- populate: getDeepPopulate2(contentTypeUid)
229
- });
230
- const status = await getVersionStatus(contentTypeUid, document);
231
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
232
- const componentsSchemas = Object.keys(
233
- attributesSchema
234
- ).reduce((currentComponentSchemas, key) => {
235
- const fieldSchema = attributesSchema[key];
236
- if (fieldSchema.type === "component") {
237
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
238
- return {
239
- ...currentComponentSchemas,
240
- [fieldSchema.component]: componentSchema
241
- };
242
- }
243
- return currentComponentSchemas;
244
- }, {});
245
- await strapi2.db.transaction(async ({ onCommit }) => {
246
- onCommit(() => {
247
- this.createVersion({
248
- contentType: contentTypeUid,
249
- data: omit(FIELDS_TO_IGNORE, document),
250
- schema: omit(FIELDS_TO_IGNORE, attributesSchema),
251
- componentsSchemas,
252
- relatedDocumentId: documentContext.documentId,
253
- locale,
254
- status
255
- });
267
+ const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
268
+ if (relatedEntry) {
269
+ currentRelationData.results.push({
270
+ ...relatedEntry,
271
+ status: await getVersionStatus(attributeSchema.target, relatedEntry)
256
272
  });
257
- });
258
- return result;
259
- });
260
- const retentionDays = getRetentionDays(strapi2);
261
- state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
262
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
263
- const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
264
- query.deleteMany({
265
- where: {
266
- created_at: {
267
- $lt: expirationDate.toISOString()
268
- }
269
- }
270
- });
271
- });
272
- state.isInitialized = true;
273
- },
274
- async destroy() {
275
- if (state.deleteExpiredJob) {
276
- state.deleteExpiredJob.cancel();
277
- }
278
- },
273
+ } else {
274
+ currentRelationData.meta.missingCount += 1;
275
+ }
276
+ return currentRelationData;
277
+ },
278
+ Promise.resolve({
279
+ results: [],
280
+ meta: { missingCount: 0 }
281
+ })
282
+ );
283
+ };
284
+ return {
285
+ getSchemaAttributesDiff,
286
+ getRelationRestoreValue,
287
+ getMediaRestoreValue,
288
+ getDefaultLocale,
289
+ getLocaleDictionary,
290
+ getRetentionDays,
291
+ getVersionStatus,
292
+ getDeepPopulate: getDeepPopulate2,
293
+ buildMediaResponse,
294
+ buildRelationReponse
295
+ };
296
+ };
297
+ const createHistoryService = ({ strapi: strapi2 }) => {
298
+ const query = strapi2.db.query(HISTORY_VERSION_UID);
299
+ const serviceUtils = createServiceUtils({ strapi: strapi2 });
300
+ return {
279
301
  async createVersion(historyVersionData) {
280
302
  await query.create({
281
303
  data: {
@@ -286,7 +308,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
286
308
  });
287
309
  },
288
310
  async findVersionsPage(params) {
289
- const locale = params.query.locale || await getDefaultLocale();
311
+ const locale = params.query.locale || await serviceUtils.getDefaultLocale();
290
312
  const [{ results, pagination }, localeDictionary] = await Promise.all([
291
313
  query.findPage({
292
314
  ...params.query,
@@ -300,78 +322,34 @@ const createHistoryService = ({ strapi: strapi2 }) => {
300
322
  populate: ["createdBy"],
301
323
  orderBy: [{ createdAt: "desc" }]
302
324
  }),
303
- getLocaleDictionary()
325
+ serviceUtils.getLocaleDictionary()
304
326
  ]);
305
- const buildRelationReponse = async (values, attributeSchema) => {
306
- return values.slice(0, 25).reduce(
307
- async (currentRelationDataPromise, entry) => {
308
- const currentRelationData = await currentRelationDataPromise;
309
- if (!entry) {
310
- return currentRelationData;
311
- }
312
- const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
313
- const permissionChecker2 = getService$1("permission-checker").create({
314
- userAbility: params.state.userAbility,
315
- model: attributeSchema.target
316
- });
317
- const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
318
- if (sanitizedEntry) {
319
- currentRelationData.results.push({
320
- ...sanitizedEntry,
321
- status: await getVersionStatus(attributeSchema.target, sanitizedEntry)
322
- });
323
- } else {
324
- currentRelationData.meta.missingCount += 1;
325
- }
326
- return currentRelationData;
327
- },
328
- Promise.resolve({
329
- results: [],
330
- meta: { missingCount: 0 }
331
- })
332
- );
333
- };
334
- const buildMediaResponse = async (values) => {
335
- return values.slice(0, 25).reduce(
336
- async (currentRelationDataPromise, entry) => {
337
- const currentRelationData = await currentRelationDataPromise;
338
- if (!entry) {
339
- return currentRelationData;
340
- }
341
- const permissionChecker2 = getService$1("permission-checker").create({
342
- userAbility: params.state.userAbility,
343
- model: "plugin::upload.file"
344
- });
345
- const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
346
- const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
347
- if (sanitizedEntry) {
348
- currentRelationData.results.push(sanitizedEntry);
349
- } else {
350
- currentRelationData.meta.missingCount += 1;
351
- }
352
- return currentRelationData;
353
- },
354
- Promise.resolve({
355
- results: [],
356
- meta: { missingCount: 0 }
357
- })
358
- );
359
- };
360
327
  const populateEntryRelations = async (entry) => {
361
328
  const entryWithRelations = await Object.entries(entry.schema).reduce(
362
329
  async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
363
330
  const attributeValue = entry.data[attributeKey];
364
331
  const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
365
332
  if (attributeSchema.type === "media") {
333
+ const permissionChecker2 = getService$1("permission-checker").create({
334
+ userAbility: params.state.userAbility,
335
+ model: "plugin::upload.file"
336
+ });
337
+ const response = await serviceUtils.buildMediaResponse(attributeValues);
338
+ const sanitizedResults = await Promise.all(
339
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
340
+ );
366
341
  return {
367
342
  ...await currentDataWithRelations,
368
- [attributeKey]: await buildMediaResponse(attributeValues)
343
+ [attributeKey]: {
344
+ results: sanitizedResults,
345
+ meta: response.meta
346
+ }
369
347
  };
370
348
  }
371
349
  if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
372
350
  if (attributeSchema.target === "admin::user") {
373
351
  const adminUsers = await Promise.all(
374
- attributeValues.map(async (userToPopulate) => {
352
+ attributeValues.map((userToPopulate) => {
375
353
  if (userToPopulate == null) {
376
354
  return null;
377
355
  }
@@ -388,9 +366,23 @@ const createHistoryService = ({ strapi: strapi2 }) => {
388
366
  [attributeKey]: adminUsers
389
367
  };
390
368
  }
369
+ const permissionChecker2 = getService$1("permission-checker").create({
370
+ userAbility: params.state.userAbility,
371
+ model: attributeSchema.target
372
+ });
373
+ const response = await serviceUtils.buildRelationReponse(
374
+ attributeValues,
375
+ attributeSchema
376
+ );
377
+ const sanitizedResults = await Promise.all(
378
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
379
+ );
391
380
  return {
392
381
  ...await currentDataWithRelations,
393
- [attributeKey]: await buildRelationReponse(attributeValues, attributeSchema)
382
+ [attributeKey]: {
383
+ results: sanitizedResults,
384
+ meta: response.meta
385
+ }
394
386
  };
395
387
  }
396
388
  return currentDataWithRelations;
@@ -405,7 +397,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
405
397
  ...result,
406
398
  data: await populateEntryRelations(result),
407
399
  meta: {
408
- unknownAttributes: getSchemaAttributesDiff(
400
+ unknownAttributes: serviceUtils.getSchemaAttributesDiff(
409
401
  result.schema,
410
402
  strapi2.getModel(params.query.contentType).attributes
411
403
  )
@@ -422,7 +414,10 @@ const createHistoryService = ({ strapi: strapi2 }) => {
422
414
  async restoreVersion(versionId) {
423
415
  const version = await query.findOne({ where: { id: versionId } });
424
416
  const contentTypeSchemaAttributes = strapi2.getModel(version.contentType).attributes;
425
- const schemaDiff = getSchemaAttributesDiff(version.schema, contentTypeSchemaAttributes);
417
+ const schemaDiff = serviceUtils.getSchemaAttributesDiff(
418
+ version.schema,
419
+ contentTypeSchemaAttributes
420
+ );
426
421
  const dataWithoutAddedAttributes = Object.keys(schemaDiff.added).reduce(
427
422
  (currentData, addedKey) => {
428
423
  currentData[addedKey] = null;
@@ -435,61 +430,26 @@ const createHistoryService = ({ strapi: strapi2 }) => {
435
430
  FIELDS_TO_IGNORE,
436
431
  contentTypeSchemaAttributes
437
432
  );
438
- const dataWithoutMissingRelations = await Object.entries(sanitizedSchemaAttributes).reduce(
439
- async (previousRelationAttributesPromise, [name, attribute]) => {
440
- const previousRelationAttributes = await previousRelationAttributesPromise;
441
- const relationData = version.data[name];
442
- if (relationData === null) {
433
+ const reducer = async.reduce(Object.entries(sanitizedSchemaAttributes));
434
+ const dataWithoutMissingRelations = await reducer(
435
+ async (previousRelationAttributes, [name, attribute]) => {
436
+ const versionRelationData = version.data[name];
437
+ if (!versionRelationData) {
443
438
  return previousRelationAttributes;
444
439
  }
445
440
  if (attribute.type === "relation" && // TODO: handle polymorphic relations
446
441
  attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
447
- if (Array.isArray(relationData)) {
448
- if (relationData.length === 0)
449
- return previousRelationAttributes;
450
- const existingAndMissingRelations = await Promise.all(
451
- relationData.map((relation) => {
452
- return strapi2.documents(attribute.target).findOne({
453
- documentId: relation.documentId,
454
- locale: relation.locale || void 0
455
- });
456
- })
457
- );
458
- const existingRelations = existingAndMissingRelations.filter(
459
- (relation) => relation !== null
460
- );
461
- previousRelationAttributes[name] = existingRelations;
462
- } else {
463
- const existingRelation = await strapi2.documents(attribute.target).findOne({
464
- documentId: relationData.documentId,
465
- locale: relationData.locale || void 0
466
- });
467
- if (!existingRelation) {
468
- previousRelationAttributes[name] = null;
469
- }
470
- }
442
+ const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
443
+ previousRelationAttributes[name] = data2;
471
444
  }
472
445
  if (attribute.type === "media") {
473
- if (attribute.multiple) {
474
- const existingAndMissingMedias = await Promise.all(
475
- // @ts-expect-error Fix the type definitions so this isn't any
476
- relationData.map((media) => {
477
- return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
478
- })
479
- );
480
- const existingMedias = existingAndMissingMedias.filter((media) => media != null);
481
- previousRelationAttributes[name] = existingMedias;
482
- } else {
483
- const existingMedia = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: version.data[name].id } });
484
- if (!existingMedia) {
485
- previousRelationAttributes[name] = null;
486
- }
487
- }
446
+ const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
447
+ previousRelationAttributes[name] = data2;
488
448
  }
489
449
  return previousRelationAttributes;
490
450
  },
491
451
  // Clone to avoid mutating the original version data
492
- Promise.resolve(structuredClone(dataWithoutAddedAttributes))
452
+ structuredClone(dataWithoutAddedAttributes)
493
453
  );
494
454
  const data = omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
495
455
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -504,8 +464,93 @@ const createHistoryService = ({ strapi: strapi2 }) => {
504
464
  }
505
465
  };
506
466
  };
467
+ const createLifecyclesService = ({ strapi: strapi2 }) => {
468
+ const state = {
469
+ deleteExpiredJob: null,
470
+ isInitialized: false
471
+ };
472
+ const query = strapi2.db.query(HISTORY_VERSION_UID);
473
+ const historyService = getService(strapi2, "history");
474
+ const serviceUtils = createServiceUtils({ strapi: strapi2 });
475
+ return {
476
+ async bootstrap() {
477
+ if (state.isInitialized) {
478
+ return;
479
+ }
480
+ strapi2.documents.use(async (context, next) => {
481
+ if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
482
+ return next();
483
+ }
484
+ if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
485
+ return next();
486
+ }
487
+ const contentTypeUid = context.contentType.uid;
488
+ if (!contentTypeUid.startsWith("api::")) {
489
+ return next();
490
+ }
491
+ const result = await next();
492
+ const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
493
+ const defaultLocale = await serviceUtils.getDefaultLocale();
494
+ const locale = documentContext.locale || defaultLocale;
495
+ const document = await strapi2.documents(contentTypeUid).findOne({
496
+ documentId: documentContext.documentId,
497
+ locale,
498
+ populate: serviceUtils.getDeepPopulate(contentTypeUid)
499
+ });
500
+ const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
501
+ const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
502
+ const componentsSchemas = Object.keys(
503
+ attributesSchema
504
+ ).reduce((currentComponentSchemas, key) => {
505
+ const fieldSchema = attributesSchema[key];
506
+ if (fieldSchema.type === "component") {
507
+ const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
508
+ return {
509
+ ...currentComponentSchemas,
510
+ [fieldSchema.component]: componentSchema
511
+ };
512
+ }
513
+ return currentComponentSchemas;
514
+ }, {});
515
+ await strapi2.db.transaction(async ({ onCommit }) => {
516
+ onCommit(() => {
517
+ historyService.createVersion({
518
+ contentType: contentTypeUid,
519
+ data: omit(FIELDS_TO_IGNORE, document),
520
+ schema: omit(FIELDS_TO_IGNORE, attributesSchema),
521
+ componentsSchemas,
522
+ relatedDocumentId: documentContext.documentId,
523
+ locale,
524
+ status
525
+ });
526
+ });
527
+ });
528
+ return result;
529
+ });
530
+ const retentionDays = serviceUtils.getRetentionDays();
531
+ state.deleteExpiredJob = scheduleJob("0 0 * * *", () => {
532
+ const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
533
+ const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
534
+ query.deleteMany({
535
+ where: {
536
+ created_at: {
537
+ $lt: expirationDate.toISOString()
538
+ }
539
+ }
540
+ });
541
+ });
542
+ state.isInitialized = true;
543
+ },
544
+ async destroy() {
545
+ if (state.deleteExpiredJob) {
546
+ state.deleteExpiredJob.cancel();
547
+ }
548
+ }
549
+ };
550
+ };
507
551
  const services$1 = {
508
- history: createHistoryService
552
+ history: createHistoryService,
553
+ lifecycles: createLifecyclesService
509
554
  };
510
555
  const info = { pluginName: "content-manager", type: "admin" };
511
556
  const historyVersionRouter = {
@@ -585,10 +630,10 @@ const getFeature = () => {
585
630
  strapi2.get("models").add(historyVersion);
586
631
  },
587
632
  bootstrap({ strapi: strapi2 }) {
588
- getService(strapi2, "history").bootstrap();
633
+ getService(strapi2, "lifecycles").bootstrap();
589
634
  },
590
635
  destroy({ strapi: strapi2 }) {
591
- getService(strapi2, "history").destroy();
636
+ getService(strapi2, "lifecycles").destroy();
592
637
  },
593
638
  controllers: controllers$1,
594
639
  services: services$1,