@strapi/content-releases 0.0.0-next.37dd1e3ff22e1635b69683abadd444912ae0dbff → 0.0.0-next.44f19b3d2f81d983c343a219aa2781ee0deecb5f
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.
- package/dist/_chunks/{App-J4jrthEu.mjs → App-3ycH2d3s.mjs} +183 -71
- package/dist/_chunks/App-3ycH2d3s.mjs.map +1 -0
- package/dist/_chunks/{App-5PRKHpa2.js → App-5PsAyVt2.js} +180 -68
- package/dist/_chunks/App-5PsAyVt2.js.map +1 -0
- package/dist/_chunks/{en-haKSQIo8.js → en-2DuPv5k0.js} +5 -1
- package/dist/_chunks/en-2DuPv5k0.js.map +1 -0
- package/dist/_chunks/{en-ngTk74JV.mjs → en-SOqjCdyh.mjs} +5 -1
- package/dist/_chunks/en-SOqjCdyh.mjs.map +1 -0
- package/dist/_chunks/{index-_Zsj8MUA.mjs → index-4gUWuCQV.mjs} +133 -52
- package/dist/_chunks/index-4gUWuCQV.mjs.map +1 -0
- package/dist/_chunks/{index-PEkKIRyJ.js → index-D57Rztnc.js} +122 -41
- package/dist/_chunks/index-D57Rztnc.js.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +3 -2
- package/dist/admin/index.mjs.map +1 -1
- package/dist/server/index.js +289 -136
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +289 -137
- package/dist/server/index.mjs.map +1 -1
- package/package.json +10 -9
- package/dist/_chunks/App-5PRKHpa2.js.map +0 -1
- package/dist/_chunks/App-J4jrthEu.mjs.map +0 -1
- package/dist/_chunks/en-haKSQIo8.js.map +0 -1
- package/dist/_chunks/en-ngTk74JV.mjs.map +0 -1
- package/dist/_chunks/index-PEkKIRyJ.js.map +0 -1
- package/dist/_chunks/index-_Zsj8MUA.mjs.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const utils = require("@strapi/utils");
|
|
3
|
+
const lodash = require("lodash");
|
|
3
4
|
const _ = require("lodash/fp");
|
|
5
|
+
const EE = require("@strapi/strapi/dist/utils/ee");
|
|
4
6
|
const yup = require("yup");
|
|
5
7
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
6
8
|
function _interopNamespace(e) {
|
|
@@ -22,6 +24,7 @@ function _interopNamespace(e) {
|
|
|
22
24
|
return Object.freeze(n);
|
|
23
25
|
}
|
|
24
26
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
27
|
+
const EE__default = /* @__PURE__ */ _interopDefault(EE);
|
|
25
28
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
26
29
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
27
30
|
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
@@ -69,40 +72,47 @@ const ACTIONS = [
|
|
|
69
72
|
pluginName: "content-releases"
|
|
70
73
|
}
|
|
71
74
|
];
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
async function deleteActionsOnDisableDraftAndPublish({
|
|
76
|
+
oldContentTypes,
|
|
77
|
+
contentTypes: contentTypes2
|
|
78
|
+
}) {
|
|
79
|
+
if (!oldContentTypes) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const uid in contentTypes2) {
|
|
83
|
+
if (!oldContentTypes[uid]) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const oldContentType = oldContentTypes[uid];
|
|
87
|
+
const contentType = contentTypes2[uid];
|
|
88
|
+
if (utils.contentTypes.hasDraftAndPublish(oldContentType) && !utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
89
|
+
await strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: uid }).execute();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
94
|
+
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
95
|
+
if (deletedContentTypes.length) {
|
|
96
|
+
await utils.mapAsync(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
97
|
+
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
75
101
|
const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
|
|
76
102
|
const register = async ({ strapi: strapi2 }) => {
|
|
77
|
-
if (features$2.isEnabled("cms-content-releases")
|
|
103
|
+
if (features$2.isEnabled("cms-content-releases")) {
|
|
78
104
|
await strapi2.admin.services.permission.actionProvider.registerMany(ACTIONS);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const destroyContentTypeUpdateListener = strapi2.eventHub.on(
|
|
82
|
-
"content-type.update",
|
|
83
|
-
async ({ contentType }) => {
|
|
84
|
-
if (contentType.schema.options.draftAndPublish === false) {
|
|
85
|
-
await releaseActionService.deleteManyForContentType(contentType.uid);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
eventManager.addDestroyListenerCallback(destroyContentTypeUpdateListener);
|
|
90
|
-
const destroyContentTypeDeleteListener = strapi2.eventHub.on(
|
|
91
|
-
"content-type.delete",
|
|
92
|
-
async ({ contentType }) => {
|
|
93
|
-
await releaseActionService.deleteManyForContentType(contentType.uid);
|
|
94
|
-
}
|
|
95
|
-
);
|
|
96
|
-
eventManager.addDestroyListenerCallback(destroyContentTypeDeleteListener);
|
|
105
|
+
strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish);
|
|
106
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType);
|
|
97
107
|
}
|
|
98
108
|
};
|
|
99
109
|
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
100
110
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
101
|
-
if (features$1.isEnabled("cms-content-releases")
|
|
111
|
+
if (features$1.isEnabled("cms-content-releases")) {
|
|
102
112
|
strapi2.db.lifecycles.subscribe({
|
|
103
113
|
afterDelete(event) {
|
|
104
114
|
const { model, result } = event;
|
|
105
|
-
if (model.kind === "collectionType" && model.options
|
|
115
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
106
116
|
const { id } = result;
|
|
107
117
|
strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
108
118
|
where: {
|
|
@@ -118,7 +128,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
118
128
|
*/
|
|
119
129
|
async beforeDeleteMany(event) {
|
|
120
130
|
const { model, params } = event;
|
|
121
|
-
if (model.kind === "collectionType" && model.options
|
|
131
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
122
132
|
const { where } = params;
|
|
123
133
|
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
124
134
|
event.state.entriesToDelete = entriesToDelete;
|
|
@@ -233,30 +243,32 @@ const contentTypes = {
|
|
|
233
243
|
release: release$1,
|
|
234
244
|
"release-action": releaseAction$1
|
|
235
245
|
};
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
where: {
|
|
240
|
-
target_type: contentTypeUid
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
});
|
|
246
|
+
const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
247
|
+
return strapi2.plugin("content-releases").service(name);
|
|
248
|
+
};
|
|
245
249
|
const getGroupName = (queryValue) => {
|
|
246
250
|
switch (queryValue) {
|
|
247
251
|
case "contentType":
|
|
248
|
-
return "
|
|
252
|
+
return "contentType.displayName";
|
|
249
253
|
case "action":
|
|
250
254
|
return "type";
|
|
251
255
|
case "locale":
|
|
252
|
-
return ___default.default.getOr("No locale", "
|
|
256
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
253
257
|
default:
|
|
254
|
-
return "
|
|
258
|
+
return "contentType.displayName";
|
|
255
259
|
}
|
|
256
260
|
};
|
|
257
261
|
const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
258
262
|
async create(releaseData, { user }) {
|
|
259
263
|
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
264
|
+
const { validatePendingReleasesLimit, validateUniqueNameForPendingRelease } = getService(
|
|
265
|
+
"release-validation",
|
|
266
|
+
{ strapi: strapi2 }
|
|
267
|
+
);
|
|
268
|
+
await Promise.all([
|
|
269
|
+
validatePendingReleasesLimit(),
|
|
270
|
+
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name)
|
|
271
|
+
]);
|
|
260
272
|
return strapi2.entityService.create(RELEASE_MODEL_UID, {
|
|
261
273
|
data: releaseWithCreatorFields
|
|
262
274
|
});
|
|
@@ -278,51 +290,66 @@ const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
|
278
290
|
}
|
|
279
291
|
});
|
|
280
292
|
},
|
|
281
|
-
async
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// Find all Releases where the content type entry is present
|
|
288
|
-
actions: {
|
|
289
|
-
target_type: contentTypeUid,
|
|
290
|
-
target_id: entryId
|
|
291
|
-
}
|
|
292
|
-
} : {
|
|
293
|
-
// Find all Releases where the content type entry is not present
|
|
294
|
-
$or: [
|
|
295
|
-
{
|
|
296
|
-
$not: {
|
|
297
|
-
actions: {
|
|
298
|
-
target_type: contentTypeUid,
|
|
299
|
-
target_id: entryId
|
|
300
|
-
}
|
|
301
|
-
}
|
|
293
|
+
async findManyWithContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
294
|
+
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
295
|
+
where: {
|
|
296
|
+
actions: {
|
|
297
|
+
target_type: contentTypeUid,
|
|
298
|
+
target_id: entryId
|
|
302
299
|
},
|
|
303
|
-
{
|
|
304
|
-
|
|
300
|
+
releasedAt: {
|
|
301
|
+
$null: true
|
|
305
302
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
303
|
+
},
|
|
304
|
+
populate: {
|
|
305
|
+
// Filter the action to get only the content type entry
|
|
306
|
+
actions: {
|
|
307
|
+
where: {
|
|
308
|
+
target_type: contentTypeUid,
|
|
309
|
+
target_id: entryId
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
return releases.map((release2) => {
|
|
315
|
+
if (release2.actions?.length) {
|
|
316
|
+
const [actionForEntry] = release2.actions;
|
|
317
|
+
delete release2.actions;
|
|
318
|
+
return {
|
|
319
|
+
...release2,
|
|
320
|
+
action: actionForEntry
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return release2;
|
|
324
|
+
});
|
|
325
|
+
},
|
|
326
|
+
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
327
|
+
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
328
|
+
where: {
|
|
329
|
+
releasedAt: {
|
|
330
|
+
$null: true
|
|
331
|
+
},
|
|
332
|
+
actions: {
|
|
312
333
|
target_type: contentTypeUid,
|
|
313
334
|
target_id: entryId
|
|
314
335
|
}
|
|
315
336
|
}
|
|
316
|
-
}
|
|
337
|
+
});
|
|
317
338
|
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
318
339
|
where: {
|
|
319
|
-
|
|
340
|
+
$or: [
|
|
341
|
+
{
|
|
342
|
+
id: {
|
|
343
|
+
$notIn: releasesRelated.map((release2) => release2.id)
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
actions: null
|
|
348
|
+
}
|
|
349
|
+
],
|
|
320
350
|
releasedAt: {
|
|
321
351
|
$null: true
|
|
322
352
|
}
|
|
323
|
-
},
|
|
324
|
-
populate: {
|
|
325
|
-
...populateAttachedAction
|
|
326
353
|
}
|
|
327
354
|
});
|
|
328
355
|
return releases.map((release2) => {
|
|
@@ -397,7 +424,9 @@ const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
|
397
424
|
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
398
425
|
...query,
|
|
399
426
|
populate: {
|
|
400
|
-
entry:
|
|
427
|
+
entry: {
|
|
428
|
+
populate: "*"
|
|
429
|
+
}
|
|
401
430
|
},
|
|
402
431
|
filters: {
|
|
403
432
|
release: releaseId
|
|
@@ -417,29 +446,32 @@ const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
|
417
446
|
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
418
447
|
contentTypeUids
|
|
419
448
|
);
|
|
420
|
-
const
|
|
421
|
-
const allLocalesDictionary = allLocales.reduce((acc, locale) => {
|
|
422
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
423
|
-
return acc;
|
|
424
|
-
}, {});
|
|
449
|
+
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
425
450
|
const formattedData = actions.map((action) => {
|
|
426
451
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
427
452
|
return {
|
|
428
453
|
...action,
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
},
|
|
435
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
436
|
-
status: action.entry.publishedAt ? "published" : "draft"
|
|
454
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
455
|
+
contentType: {
|
|
456
|
+
displayName,
|
|
457
|
+
mainFieldValue: action.entry[mainField],
|
|
458
|
+
uid: action.contentType
|
|
437
459
|
}
|
|
438
460
|
};
|
|
439
461
|
});
|
|
440
462
|
const groupName = getGroupName(groupBy);
|
|
441
463
|
return ___default.default.groupBy(groupName)(formattedData);
|
|
442
464
|
},
|
|
465
|
+
async getLocalesDataForActions() {
|
|
466
|
+
if (!strapi2.plugin("i18n")) {
|
|
467
|
+
return {};
|
|
468
|
+
}
|
|
469
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
470
|
+
return allLocales.reduce((acc, locale) => {
|
|
471
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
472
|
+
return acc;
|
|
473
|
+
}, {});
|
|
474
|
+
},
|
|
443
475
|
async getContentTypesDataForActions(contentTypesUids) {
|
|
444
476
|
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
445
477
|
const contentTypesData = {};
|
|
@@ -454,6 +486,34 @@ const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
|
454
486
|
}
|
|
455
487
|
return contentTypesData;
|
|
456
488
|
},
|
|
489
|
+
getContentTypeModelsFromActions(actions) {
|
|
490
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
491
|
+
if (!acc.includes(action.contentType)) {
|
|
492
|
+
acc.push(action.contentType);
|
|
493
|
+
}
|
|
494
|
+
return acc;
|
|
495
|
+
}, []);
|
|
496
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
497
|
+
(acc, contentTypeUid) => {
|
|
498
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
499
|
+
return acc;
|
|
500
|
+
},
|
|
501
|
+
{}
|
|
502
|
+
);
|
|
503
|
+
return contentTypeModelsMap;
|
|
504
|
+
},
|
|
505
|
+
async getAllComponents() {
|
|
506
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
507
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
508
|
+
const componentsMap = components.reduce(
|
|
509
|
+
(acc, component) => {
|
|
510
|
+
acc[component.uid] = component;
|
|
511
|
+
return acc;
|
|
512
|
+
},
|
|
513
|
+
{}
|
|
514
|
+
);
|
|
515
|
+
return componentsMap;
|
|
516
|
+
},
|
|
457
517
|
async delete(releaseId) {
|
|
458
518
|
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
459
519
|
populate: {
|
|
@@ -488,7 +548,9 @@ const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
|
488
548
|
populate: {
|
|
489
549
|
actions: {
|
|
490
550
|
populate: {
|
|
491
|
-
entry:
|
|
551
|
+
entry: {
|
|
552
|
+
fields: ["id"]
|
|
553
|
+
}
|
|
492
554
|
}
|
|
493
555
|
}
|
|
494
556
|
}
|
|
@@ -503,30 +565,80 @@ const createReleaseService = ({ strapi: strapi2 }) => ({
|
|
|
503
565
|
if (releaseWithPopulatedActionEntries.actions.length === 0) {
|
|
504
566
|
throw new utils.errors.ValidationError("No entries to publish");
|
|
505
567
|
}
|
|
506
|
-
const
|
|
568
|
+
const collectionTypeActions = {};
|
|
569
|
+
const singleTypeActions = [];
|
|
507
570
|
for (const action of releaseWithPopulatedActionEntries.actions) {
|
|
508
571
|
const contentTypeUid = action.contentType;
|
|
509
|
-
if (
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
572
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
573
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
574
|
+
collectionTypeActions[contentTypeUid] = {
|
|
575
|
+
entriestoPublishIds: [],
|
|
576
|
+
entriesToUnpublishIds: []
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
if (action.type === "publish") {
|
|
580
|
+
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
581
|
+
} else {
|
|
582
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
583
|
+
}
|
|
517
584
|
} else {
|
|
518
|
-
|
|
585
|
+
singleTypeActions.push({
|
|
586
|
+
uid: contentTypeUid,
|
|
587
|
+
action: action.type,
|
|
588
|
+
id: action.entry.id
|
|
589
|
+
});
|
|
519
590
|
}
|
|
520
591
|
}
|
|
521
592
|
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
593
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
522
594
|
await strapi2.db.transaction(async () => {
|
|
523
|
-
for (const
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
595
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
596
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
597
|
+
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
598
|
+
try {
|
|
599
|
+
if (action === "publish") {
|
|
600
|
+
await entityManagerService.publish(entry, uid);
|
|
601
|
+
} else {
|
|
602
|
+
await entityManagerService.unpublish(entry, uid);
|
|
603
|
+
}
|
|
604
|
+
} catch (error) {
|
|
605
|
+
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
606
|
+
;
|
|
607
|
+
else {
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
527
610
|
}
|
|
528
|
-
|
|
529
|
-
|
|
611
|
+
}
|
|
612
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
613
|
+
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
614
|
+
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
615
|
+
const entriesToPublish = await strapi2.entityService.findMany(
|
|
616
|
+
contentTypeUid,
|
|
617
|
+
{
|
|
618
|
+
filters: {
|
|
619
|
+
id: {
|
|
620
|
+
$in: entriestoPublishIds
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
populate
|
|
624
|
+
}
|
|
625
|
+
);
|
|
626
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
627
|
+
contentTypeUid,
|
|
628
|
+
{
|
|
629
|
+
filters: {
|
|
630
|
+
id: {
|
|
631
|
+
$in: entriesToUnpublishIds
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
populate
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
if (entriesToPublish.length > 0) {
|
|
638
|
+
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
639
|
+
}
|
|
640
|
+
if (entriesToUnpublish.length > 0) {
|
|
641
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, contentTypeUid);
|
|
530
642
|
}
|
|
531
643
|
}
|
|
532
644
|
});
|
|
@@ -608,31 +720,41 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
608
720
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
609
721
|
);
|
|
610
722
|
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
if (!state.destroyListenerCallbacks.length) {
|
|
623
|
-
return;
|
|
723
|
+
},
|
|
724
|
+
async validatePendingReleasesLimit() {
|
|
725
|
+
const maximumPendingReleases = (
|
|
726
|
+
// @ts-expect-error - options is not typed into features
|
|
727
|
+
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
728
|
+
);
|
|
729
|
+
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
730
|
+
filters: {
|
|
731
|
+
releasedAt: {
|
|
732
|
+
$null: true
|
|
733
|
+
}
|
|
624
734
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
735
|
+
});
|
|
736
|
+
if (pendingReleasesCount >= maximumPendingReleases) {
|
|
737
|
+
throw new utils.errors.ValidationError("You have reached the maximum number of pending releases");
|
|
628
738
|
}
|
|
629
|
-
}
|
|
630
|
-
|
|
739
|
+
},
|
|
740
|
+
async validateUniqueNameForPendingRelease(name) {
|
|
741
|
+
const pendingReleases = await strapi2.entityService.findMany(RELEASE_MODEL_UID, {
|
|
742
|
+
filters: {
|
|
743
|
+
releasedAt: {
|
|
744
|
+
$null: true
|
|
745
|
+
},
|
|
746
|
+
name
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
const isNameUnique = pendingReleases.length === 0;
|
|
750
|
+
if (!isNameUnique) {
|
|
751
|
+
throw new utils.errors.ValidationError(`Release with name ${name} already exists`);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
});
|
|
631
755
|
const services = {
|
|
632
756
|
release: createReleaseService,
|
|
633
|
-
"release-
|
|
634
|
-
"release-validation": createReleaseValidationService,
|
|
635
|
-
"event-manager": createEventManagerService
|
|
757
|
+
"release-validation": createReleaseValidationService
|
|
636
758
|
};
|
|
637
759
|
const RELEASE_SCHEMA = yup__namespace.object().shape({
|
|
638
760
|
name: yup__namespace.string().trim().required()
|
|
@@ -652,9 +774,7 @@ const releaseController = {
|
|
|
652
774
|
const contentTypeUid = query.contentTypeUid;
|
|
653
775
|
const entryId = query.entryId;
|
|
654
776
|
const hasEntryAttached = typeof query.hasEntryAttached === "string" ? JSON.parse(query.hasEntryAttached) : false;
|
|
655
|
-
const data = await releaseService.
|
|
656
|
-
hasEntryAttached
|
|
657
|
-
});
|
|
777
|
+
const data = hasEntryAttached ? await releaseService.findManyWithContentTypeEntryAttached(contentTypeUid, entryId) : await releaseService.findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId);
|
|
658
778
|
ctx.body = { data };
|
|
659
779
|
} else {
|
|
660
780
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
@@ -742,8 +862,27 @@ const releaseController = {
|
|
|
742
862
|
const id = ctx.params.id;
|
|
743
863
|
const releaseService = getService("release", { strapi });
|
|
744
864
|
const release2 = await releaseService.publish(id, { user });
|
|
865
|
+
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
866
|
+
releaseService.countActions({
|
|
867
|
+
filters: {
|
|
868
|
+
release: id,
|
|
869
|
+
type: "publish"
|
|
870
|
+
}
|
|
871
|
+
}),
|
|
872
|
+
releaseService.countActions({
|
|
873
|
+
filters: {
|
|
874
|
+
release: id,
|
|
875
|
+
type: "unpublish"
|
|
876
|
+
}
|
|
877
|
+
})
|
|
878
|
+
]);
|
|
745
879
|
ctx.body = {
|
|
746
|
-
data: release2
|
|
880
|
+
data: release2,
|
|
881
|
+
meta: {
|
|
882
|
+
totalEntries: countPublishActions + countUnpublishActions,
|
|
883
|
+
totalPublishedEntries: countPublishActions,
|
|
884
|
+
totalUnpublishedEntries: countUnpublishActions
|
|
885
|
+
}
|
|
747
886
|
};
|
|
748
887
|
}
|
|
749
888
|
};
|
|
@@ -782,11 +921,30 @@ const releaseActionController = {
|
|
|
782
921
|
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
783
922
|
...query
|
|
784
923
|
});
|
|
785
|
-
const
|
|
924
|
+
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
925
|
+
if (acc[action.contentType]) {
|
|
926
|
+
return acc;
|
|
927
|
+
}
|
|
928
|
+
const contentTypePermissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
929
|
+
ability: ctx.state.userAbility,
|
|
930
|
+
model: action.contentType
|
|
931
|
+
});
|
|
932
|
+
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
933
|
+
return acc;
|
|
934
|
+
}, {});
|
|
935
|
+
const sanitizedResults = await utils.mapAsync(results, async (action) => ({
|
|
936
|
+
...action,
|
|
937
|
+
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
938
|
+
}));
|
|
939
|
+
const groupedData = await releaseService.groupActions(sanitizedResults, query.groupBy);
|
|
940
|
+
const contentTypes2 = releaseService.getContentTypeModelsFromActions(results);
|
|
941
|
+
const components = await releaseService.getAllComponents();
|
|
786
942
|
ctx.body = {
|
|
787
943
|
data: groupedData,
|
|
788
944
|
meta: {
|
|
789
|
-
pagination
|
|
945
|
+
pagination,
|
|
946
|
+
contentTypes: contentTypes2,
|
|
947
|
+
components
|
|
790
948
|
}
|
|
791
949
|
};
|
|
792
950
|
},
|
|
@@ -992,19 +1150,14 @@ const routes = {
|
|
|
992
1150
|
};
|
|
993
1151
|
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
994
1152
|
const getPlugin = () => {
|
|
995
|
-
if (features.isEnabled("cms-content-releases")
|
|
1153
|
+
if (features.isEnabled("cms-content-releases")) {
|
|
996
1154
|
return {
|
|
997
1155
|
register,
|
|
998
1156
|
bootstrap,
|
|
999
1157
|
contentTypes,
|
|
1000
1158
|
services,
|
|
1001
1159
|
controllers,
|
|
1002
|
-
routes
|
|
1003
|
-
destroy() {
|
|
1004
|
-
if (features.isEnabled("cms-content-releases") && strapi.features.future.isEnabled("contentReleases")) {
|
|
1005
|
-
getService("event-manager").destroyAllListeners();
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1160
|
+
routes
|
|
1008
1161
|
};
|
|
1009
1162
|
}
|
|
1010
1163
|
return {
|