@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
@@ -138,40 +138,65 @@ const FIELDS_TO_IGNORE = [
138
138
  "strapi_stage",
139
139
  "strapi_assignee"
140
140
  ];
141
- const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
142
- const sanitizedContentTypeSchemaAttributes = fp.omit(FIELDS_TO_IGNORE, contentTypeSchemaAttributes);
143
- const reduceDifferenceToAttributesObject = (diffKeys, source) => {
144
- return diffKeys.reduce((previousAttributesObject, diffKey) => {
145
- previousAttributesObject[diffKey] = source[diffKey];
146
- return previousAttributesObject;
147
- }, {});
148
- };
149
- const versionSchemaKeys = Object.keys(versionSchemaAttributes);
150
- const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
151
- const uniqueToContentType = fp.difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
152
- const added = reduceDifferenceToAttributesObject(
153
- uniqueToContentType,
154
- sanitizedContentTypeSchemaAttributes
155
- );
156
- const uniqueToVersion = fp.difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
157
- const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
158
- return { added, removed };
159
- };
160
141
  const DEFAULT_RETENTION_DAYS = 90;
161
- const createHistoryService = ({ strapi: strapi2 }) => {
162
- const state = {
163
- deleteExpiredJob: null,
164
- isInitialized: false
142
+ const createServiceUtils = ({ strapi: strapi2 }) => {
143
+ const getSchemaAttributesDiff = (versionSchemaAttributes, contentTypeSchemaAttributes) => {
144
+ const sanitizedContentTypeSchemaAttributes = fp.omit(
145
+ FIELDS_TO_IGNORE,
146
+ contentTypeSchemaAttributes
147
+ );
148
+ const reduceDifferenceToAttributesObject = (diffKeys, source) => {
149
+ return diffKeys.reduce(
150
+ (previousAttributesObject, diffKey) => {
151
+ previousAttributesObject[diffKey] = source[diffKey];
152
+ return previousAttributesObject;
153
+ },
154
+ {}
155
+ );
156
+ };
157
+ const versionSchemaKeys = Object.keys(versionSchemaAttributes);
158
+ const contentTypeSchemaAttributesKeys = Object.keys(sanitizedContentTypeSchemaAttributes);
159
+ const uniqueToContentType = fp.difference(contentTypeSchemaAttributesKeys, versionSchemaKeys);
160
+ const added = reduceDifferenceToAttributesObject(
161
+ uniqueToContentType,
162
+ sanitizedContentTypeSchemaAttributes
163
+ );
164
+ const uniqueToVersion = fp.difference(versionSchemaKeys, contentTypeSchemaAttributesKeys);
165
+ const removed = reduceDifferenceToAttributesObject(uniqueToVersion, versionSchemaAttributes);
166
+ return { added, removed };
165
167
  };
166
- const query = strapi2.db.query(HISTORY_VERSION_UID);
167
- const getRetentionDays = (strapi22) => {
168
- const featureConfig = strapi22.ee.features.get("cms-content-history");
169
- const licenseRetentionDays = typeof featureConfig === "object" && featureConfig?.options.retentionDays;
170
- const userRetentionDays = strapi22.config.get("admin.history.retentionDays");
171
- if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
172
- return userRetentionDays;
168
+ const getRelationRestoreValue = async (versionRelationData, attribute) => {
169
+ if (Array.isArray(versionRelationData)) {
170
+ if (versionRelationData.length === 0)
171
+ return versionRelationData;
172
+ const existingAndMissingRelations = await Promise.all(
173
+ versionRelationData.map((relation) => {
174
+ return strapi2.documents(attribute.target).findOne({
175
+ documentId: relation.documentId,
176
+ locale: relation.locale || void 0
177
+ });
178
+ })
179
+ );
180
+ return existingAndMissingRelations.filter(
181
+ (relation) => relation !== null
182
+ );
173
183
  }
174
- return Math.min(licenseRetentionDays, DEFAULT_RETENTION_DAYS);
184
+ return strapi2.documents(attribute.target).findOne({
185
+ documentId: versionRelationData.documentId,
186
+ locale: versionRelationData.locale || void 0
187
+ });
188
+ };
189
+ const getMediaRestoreValue = async (versionRelationData, attribute) => {
190
+ if (attribute.multiple) {
191
+ const existingAndMissingMedias = await Promise.all(
192
+ // @ts-expect-error Fix the type definitions so this isn't any
193
+ versionRelationData.map((media) => {
194
+ return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
195
+ })
196
+ );
197
+ return existingAndMissingMedias.filter((media) => media != null);
198
+ }
199
+ return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
175
200
  };
176
201
  const localesService = strapi2.plugin("i18n")?.service("locales");
177
202
  const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
@@ -187,6 +212,15 @@ const createHistoryService = ({ strapi: strapi2 }) => {
187
212
  {}
188
213
  );
189
214
  };
215
+ const getRetentionDays = () => {
216
+ const featureConfig = strapi2.ee.features.get("cms-content-history");
217
+ const licenseRetentionDays = typeof featureConfig === "object" && featureConfig?.options.retentionDays;
218
+ const userRetentionDays = strapi2.config.get("admin.history.retentionDays");
219
+ if (userRetentionDays && userRetentionDays < licenseRetentionDays) {
220
+ return userRetentionDays;
221
+ }
222
+ return Math.min(licenseRetentionDays, DEFAULT_RETENTION_DAYS);
223
+ };
190
224
  const getVersionStatus = async (contentTypeUid, document) => {
191
225
  const documentMetadataService = strapi2.plugin("content-manager").service("document-metadata");
192
226
  const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
@@ -228,80 +262,68 @@ const createHistoryService = ({ strapi: strapi2 }) => {
228
262
  return acc;
229
263
  }, {});
230
264
  };
231
- return {
232
- async bootstrap() {
233
- if (state.isInitialized) {
234
- return;
235
- }
236
- strapi2.documents.use(async (context, next) => {
237
- if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
238
- return next();
265
+ const buildMediaResponse = async (values) => {
266
+ return values.slice(0, 25).reduce(
267
+ async (currentRelationDataPromise, entry) => {
268
+ const currentRelationData = await currentRelationDataPromise;
269
+ if (!entry) {
270
+ return currentRelationData;
239
271
  }
240
- if (context.action !== "create" && context.action !== "update" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
241
- return next();
272
+ const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
273
+ if (relatedEntry) {
274
+ currentRelationData.results.push(relatedEntry);
275
+ } else {
276
+ currentRelationData.meta.missingCount += 1;
242
277
  }
243
- const contentTypeUid = context.contentType.uid;
244
- if (!contentTypeUid.startsWith("api::")) {
245
- return next();
278
+ return currentRelationData;
279
+ },
280
+ Promise.resolve({
281
+ results: [],
282
+ meta: { missingCount: 0 }
283
+ })
284
+ );
285
+ };
286
+ const buildRelationReponse = async (values, attributeSchema) => {
287
+ return values.slice(0, 25).reduce(
288
+ async (currentRelationDataPromise, entry) => {
289
+ const currentRelationData = await currentRelationDataPromise;
290
+ if (!entry) {
291
+ return currentRelationData;
246
292
  }
247
- const result = await next();
248
- const documentContext = context.action === "create" ? { documentId: result.documentId, locale: context.params?.locale } : { documentId: context.params.documentId, locale: context.params?.locale };
249
- const defaultLocale = await getDefaultLocale();
250
- const locale = documentContext.locale || defaultLocale;
251
- const document = await strapi2.documents(contentTypeUid).findOne({
252
- documentId: documentContext.documentId,
253
- locale,
254
- populate: getDeepPopulate2(contentTypeUid)
255
- });
256
- const status = await getVersionStatus(contentTypeUid, document);
257
- const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
258
- const componentsSchemas = Object.keys(
259
- attributesSchema
260
- ).reduce((currentComponentSchemas, key) => {
261
- const fieldSchema = attributesSchema[key];
262
- if (fieldSchema.type === "component") {
263
- const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
264
- return {
265
- ...currentComponentSchemas,
266
- [fieldSchema.component]: componentSchema
267
- };
268
- }
269
- return currentComponentSchemas;
270
- }, {});
271
- await strapi2.db.transaction(async ({ onCommit }) => {
272
- onCommit(() => {
273
- this.createVersion({
274
- contentType: contentTypeUid,
275
- data: fp.omit(FIELDS_TO_IGNORE, document),
276
- schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
277
- componentsSchemas,
278
- relatedDocumentId: documentContext.documentId,
279
- locale,
280
- status
281
- });
293
+ const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
294
+ if (relatedEntry) {
295
+ currentRelationData.results.push({
296
+ ...relatedEntry,
297
+ status: await getVersionStatus(attributeSchema.target, relatedEntry)
282
298
  });
283
- });
284
- return result;
285
- });
286
- const retentionDays = getRetentionDays(strapi2);
287
- state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
288
- const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
289
- const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
290
- query.deleteMany({
291
- where: {
292
- created_at: {
293
- $lt: expirationDate.toISOString()
294
- }
295
- }
296
- });
297
- });
298
- state.isInitialized = true;
299
- },
300
- async destroy() {
301
- if (state.deleteExpiredJob) {
302
- state.deleteExpiredJob.cancel();
303
- }
304
- },
299
+ } else {
300
+ currentRelationData.meta.missingCount += 1;
301
+ }
302
+ return currentRelationData;
303
+ },
304
+ Promise.resolve({
305
+ results: [],
306
+ meta: { missingCount: 0 }
307
+ })
308
+ );
309
+ };
310
+ return {
311
+ getSchemaAttributesDiff,
312
+ getRelationRestoreValue,
313
+ getMediaRestoreValue,
314
+ getDefaultLocale,
315
+ getLocaleDictionary,
316
+ getRetentionDays,
317
+ getVersionStatus,
318
+ getDeepPopulate: getDeepPopulate2,
319
+ buildMediaResponse,
320
+ buildRelationReponse
321
+ };
322
+ };
323
+ const createHistoryService = ({ strapi: strapi2 }) => {
324
+ const query = strapi2.db.query(HISTORY_VERSION_UID);
325
+ const serviceUtils = createServiceUtils({ strapi: strapi2 });
326
+ return {
305
327
  async createVersion(historyVersionData) {
306
328
  await query.create({
307
329
  data: {
@@ -312,7 +334,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
312
334
  });
313
335
  },
314
336
  async findVersionsPage(params) {
315
- const locale = params.query.locale || await getDefaultLocale();
337
+ const locale = params.query.locale || await serviceUtils.getDefaultLocale();
316
338
  const [{ results, pagination }, localeDictionary] = await Promise.all([
317
339
  query.findPage({
318
340
  ...params.query,
@@ -326,78 +348,34 @@ const createHistoryService = ({ strapi: strapi2 }) => {
326
348
  populate: ["createdBy"],
327
349
  orderBy: [{ createdAt: "desc" }]
328
350
  }),
329
- getLocaleDictionary()
351
+ serviceUtils.getLocaleDictionary()
330
352
  ]);
331
- const buildRelationReponse = async (values, attributeSchema) => {
332
- return values.slice(0, 25).reduce(
333
- async (currentRelationDataPromise, entry) => {
334
- const currentRelationData = await currentRelationDataPromise;
335
- if (!entry) {
336
- return currentRelationData;
337
- }
338
- const relatedEntry = await strapi2.documents(attributeSchema.target).findOne({ documentId: entry.documentId, locale: entry.locale || void 0 });
339
- const permissionChecker2 = getService$1("permission-checker").create({
340
- userAbility: params.state.userAbility,
341
- model: attributeSchema.target
342
- });
343
- const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
344
- if (sanitizedEntry) {
345
- currentRelationData.results.push({
346
- ...sanitizedEntry,
347
- status: await getVersionStatus(attributeSchema.target, sanitizedEntry)
348
- });
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
- const buildMediaResponse = async (values) => {
361
- return values.slice(0, 25).reduce(
362
- async (currentRelationDataPromise, entry) => {
363
- const currentRelationData = await currentRelationDataPromise;
364
- if (!entry) {
365
- return currentRelationData;
366
- }
367
- const permissionChecker2 = getService$1("permission-checker").create({
368
- userAbility: params.state.userAbility,
369
- model: "plugin::upload.file"
370
- });
371
- const relatedEntry = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: entry.id } });
372
- const sanitizedEntry = await permissionChecker2.sanitizeOutput(relatedEntry);
373
- if (sanitizedEntry) {
374
- currentRelationData.results.push(sanitizedEntry);
375
- } else {
376
- currentRelationData.meta.missingCount += 1;
377
- }
378
- return currentRelationData;
379
- },
380
- Promise.resolve({
381
- results: [],
382
- meta: { missingCount: 0 }
383
- })
384
- );
385
- };
386
353
  const populateEntryRelations = async (entry) => {
387
354
  const entryWithRelations = await Object.entries(entry.schema).reduce(
388
355
  async (currentDataWithRelations, [attributeKey, attributeSchema]) => {
389
356
  const attributeValue = entry.data[attributeKey];
390
357
  const attributeValues = Array.isArray(attributeValue) ? attributeValue : [attributeValue];
391
358
  if (attributeSchema.type === "media") {
359
+ const permissionChecker2 = getService$1("permission-checker").create({
360
+ userAbility: params.state.userAbility,
361
+ model: "plugin::upload.file"
362
+ });
363
+ const response = await serviceUtils.buildMediaResponse(attributeValues);
364
+ const sanitizedResults = await Promise.all(
365
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
366
+ );
392
367
  return {
393
368
  ...await currentDataWithRelations,
394
- [attributeKey]: await buildMediaResponse(attributeValues)
369
+ [attributeKey]: {
370
+ results: sanitizedResults,
371
+ meta: response.meta
372
+ }
395
373
  };
396
374
  }
397
375
  if (attributeSchema.type === "relation" && attributeSchema.relation !== "morphToOne" && attributeSchema.relation !== "morphToMany") {
398
376
  if (attributeSchema.target === "admin::user") {
399
377
  const adminUsers = await Promise.all(
400
- attributeValues.map(async (userToPopulate) => {
378
+ attributeValues.map((userToPopulate) => {
401
379
  if (userToPopulate == null) {
402
380
  return null;
403
381
  }
@@ -414,9 +392,23 @@ const createHistoryService = ({ strapi: strapi2 }) => {
414
392
  [attributeKey]: adminUsers
415
393
  };
416
394
  }
395
+ const permissionChecker2 = getService$1("permission-checker").create({
396
+ userAbility: params.state.userAbility,
397
+ model: attributeSchema.target
398
+ });
399
+ const response = await serviceUtils.buildRelationReponse(
400
+ attributeValues,
401
+ attributeSchema
402
+ );
403
+ const sanitizedResults = await Promise.all(
404
+ response.results.map((media) => permissionChecker2.sanitizeOutput(media))
405
+ );
417
406
  return {
418
407
  ...await currentDataWithRelations,
419
- [attributeKey]: await buildRelationReponse(attributeValues, attributeSchema)
408
+ [attributeKey]: {
409
+ results: sanitizedResults,
410
+ meta: response.meta
411
+ }
420
412
  };
421
413
  }
422
414
  return currentDataWithRelations;
@@ -431,7 +423,7 @@ const createHistoryService = ({ strapi: strapi2 }) => {
431
423
  ...result,
432
424
  data: await populateEntryRelations(result),
433
425
  meta: {
434
- unknownAttributes: getSchemaAttributesDiff(
426
+ unknownAttributes: serviceUtils.getSchemaAttributesDiff(
435
427
  result.schema,
436
428
  strapi2.getModel(params.query.contentType).attributes
437
429
  )
@@ -448,7 +440,10 @@ const createHistoryService = ({ strapi: strapi2 }) => {
448
440
  async restoreVersion(versionId) {
449
441
  const version = await query.findOne({ where: { id: versionId } });
450
442
  const contentTypeSchemaAttributes = strapi2.getModel(version.contentType).attributes;
451
- const schemaDiff = getSchemaAttributesDiff(version.schema, contentTypeSchemaAttributes);
443
+ const schemaDiff = serviceUtils.getSchemaAttributesDiff(
444
+ version.schema,
445
+ contentTypeSchemaAttributes
446
+ );
452
447
  const dataWithoutAddedAttributes = Object.keys(schemaDiff.added).reduce(
453
448
  (currentData, addedKey) => {
454
449
  currentData[addedKey] = null;
@@ -461,61 +456,26 @@ const createHistoryService = ({ strapi: strapi2 }) => {
461
456
  FIELDS_TO_IGNORE,
462
457
  contentTypeSchemaAttributes
463
458
  );
464
- const dataWithoutMissingRelations = await Object.entries(sanitizedSchemaAttributes).reduce(
465
- async (previousRelationAttributesPromise, [name, attribute]) => {
466
- const previousRelationAttributes = await previousRelationAttributesPromise;
467
- const relationData = version.data[name];
468
- if (relationData === null) {
459
+ const reducer = strapiUtils.async.reduce(Object.entries(sanitizedSchemaAttributes));
460
+ const dataWithoutMissingRelations = await reducer(
461
+ async (previousRelationAttributes, [name, attribute]) => {
462
+ const versionRelationData = version.data[name];
463
+ if (!versionRelationData) {
469
464
  return previousRelationAttributes;
470
465
  }
471
466
  if (attribute.type === "relation" && // TODO: handle polymorphic relations
472
467
  attribute.relation !== "morphToOne" && attribute.relation !== "morphToMany") {
473
- if (Array.isArray(relationData)) {
474
- if (relationData.length === 0)
475
- return previousRelationAttributes;
476
- const existingAndMissingRelations = await Promise.all(
477
- relationData.map((relation) => {
478
- return strapi2.documents(attribute.target).findOne({
479
- documentId: relation.documentId,
480
- locale: relation.locale || void 0
481
- });
482
- })
483
- );
484
- const existingRelations = existingAndMissingRelations.filter(
485
- (relation) => relation !== null
486
- );
487
- previousRelationAttributes[name] = existingRelations;
488
- } else {
489
- const existingRelation = await strapi2.documents(attribute.target).findOne({
490
- documentId: relationData.documentId,
491
- locale: relationData.locale || void 0
492
- });
493
- if (!existingRelation) {
494
- previousRelationAttributes[name] = null;
495
- }
496
- }
468
+ const data2 = await serviceUtils.getRelationRestoreValue(versionRelationData, attribute);
469
+ previousRelationAttributes[name] = data2;
497
470
  }
498
471
  if (attribute.type === "media") {
499
- if (attribute.multiple) {
500
- const existingAndMissingMedias = await Promise.all(
501
- // @ts-expect-error Fix the type definitions so this isn't any
502
- relationData.map((media) => {
503
- return strapi2.db.query("plugin::upload.file").findOne({ where: { id: media.id } });
504
- })
505
- );
506
- const existingMedias = existingAndMissingMedias.filter((media) => media != null);
507
- previousRelationAttributes[name] = existingMedias;
508
- } else {
509
- const existingMedia = await strapi2.db.query("plugin::upload.file").findOne({ where: { id: version.data[name].id } });
510
- if (!existingMedia) {
511
- previousRelationAttributes[name] = null;
512
- }
513
- }
472
+ const data2 = await serviceUtils.getMediaRestoreValue(versionRelationData, attribute);
473
+ previousRelationAttributes[name] = data2;
514
474
  }
515
475
  return previousRelationAttributes;
516
476
  },
517
477
  // Clone to avoid mutating the original version data
518
- Promise.resolve(structuredClone(dataWithoutAddedAttributes))
478
+ structuredClone(dataWithoutAddedAttributes)
519
479
  );
520
480
  const data = fp.omit(["id", ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
521
481
  const restoredDocument = await strapi2.documents(version.contentType).update({
@@ -530,8 +490,93 @@ const createHistoryService = ({ strapi: strapi2 }) => {
530
490
  }
531
491
  };
532
492
  };
493
+ const createLifecyclesService = ({ strapi: strapi2 }) => {
494
+ const state = {
495
+ deleteExpiredJob: null,
496
+ isInitialized: false
497
+ };
498
+ const query = strapi2.db.query(HISTORY_VERSION_UID);
499
+ const historyService = getService(strapi2, "history");
500
+ const serviceUtils = createServiceUtils({ strapi: strapi2 });
501
+ return {
502
+ async bootstrap() {
503
+ if (state.isInitialized) {
504
+ return;
505
+ }
506
+ 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
+ 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 };
519
+ const defaultLocale = await serviceUtils.getDefaultLocale();
520
+ const locale = documentContext.locale || defaultLocale;
521
+ const document = await strapi2.documents(contentTypeUid).findOne({
522
+ documentId: documentContext.documentId,
523
+ locale,
524
+ populate: serviceUtils.getDeepPopulate(contentTypeUid)
525
+ });
526
+ const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
527
+ const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
528
+ const componentsSchemas = Object.keys(
529
+ attributesSchema
530
+ ).reduce((currentComponentSchemas, key) => {
531
+ const fieldSchema = attributesSchema[key];
532
+ if (fieldSchema.type === "component") {
533
+ const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
534
+ return {
535
+ ...currentComponentSchemas,
536
+ [fieldSchema.component]: componentSchema
537
+ };
538
+ }
539
+ return currentComponentSchemas;
540
+ }, {});
541
+ await strapi2.db.transaction(async ({ onCommit }) => {
542
+ onCommit(() => {
543
+ historyService.createVersion({
544
+ contentType: contentTypeUid,
545
+ data: fp.omit(FIELDS_TO_IGNORE, document),
546
+ schema: fp.omit(FIELDS_TO_IGNORE, attributesSchema),
547
+ componentsSchemas,
548
+ relatedDocumentId: documentContext.documentId,
549
+ locale,
550
+ status
551
+ });
552
+ });
553
+ });
554
+ return result;
555
+ });
556
+ const retentionDays = serviceUtils.getRetentionDays();
557
+ state.deleteExpiredJob = nodeSchedule.scheduleJob("0 0 * * *", () => {
558
+ const retentionDaysInMilliseconds = retentionDays * 24 * 60 * 60 * 1e3;
559
+ const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
560
+ query.deleteMany({
561
+ where: {
562
+ created_at: {
563
+ $lt: expirationDate.toISOString()
564
+ }
565
+ }
566
+ });
567
+ });
568
+ state.isInitialized = true;
569
+ },
570
+ async destroy() {
571
+ if (state.deleteExpiredJob) {
572
+ state.deleteExpiredJob.cancel();
573
+ }
574
+ }
575
+ };
576
+ };
533
577
  const services$1 = {
534
- history: createHistoryService
578
+ history: createHistoryService,
579
+ lifecycles: createLifecyclesService
535
580
  };
536
581
  const info = { pluginName: "content-manager", type: "admin" };
537
582
  const historyVersionRouter = {
@@ -611,10 +656,10 @@ const getFeature = () => {
611
656
  strapi2.get("models").add(historyVersion);
612
657
  },
613
658
  bootstrap({ strapi: strapi2 }) {
614
- getService(strapi2, "history").bootstrap();
659
+ getService(strapi2, "lifecycles").bootstrap();
615
660
  },
616
661
  destroy({ strapi: strapi2 }) {
617
- getService(strapi2, "history").destroy();
662
+ getService(strapi2, "lifecycles").destroy();
618
663
  },
619
664
  controllers: controllers$1,
620
665
  services: services$1,