@strapi/content-releases 0.0.0-experimental.fc1ac2acd58c8a5a858679956b6d102ac5ee4011 → 0.0.0-experimental.fea7af0bd6b406e4648e4c6669829249f73eb60f
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-C768ulk4.js → App-HjWtUYmc.js} +233 -261
- package/dist/_chunks/App-HjWtUYmc.js.map +1 -0
- package/dist/_chunks/{App-0Er6xxcq.mjs → App-gu1aiP6i.mjs} +237 -265
- package/dist/_chunks/App-gu1aiP6i.mjs.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-3tRbmbY3.mjs} +2 -2
- package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-bpIYXOfu.js} +2 -2
- package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +1 -0
- package/dist/_chunks/{en-gcJJ5htG.js → en-HrREghh3.js} +11 -3
- package/dist/_chunks/en-HrREghh3.js.map +1 -0
- package/dist/_chunks/{en-WuuhP6Bn.mjs → en-ltT1TlKQ.mjs} +11 -3
- package/dist/_chunks/en-ltT1TlKQ.mjs.map +1 -0
- package/dist/_chunks/{index-BLSMpbpZ.js → index-ZNwxYN8H.js} +338 -31
- package/dist/_chunks/index-ZNwxYN8H.js.map +1 -0
- package/dist/_chunks/{index-fJx1up7m.mjs → index-mvj9PSKd.mjs} +345 -38
- package/dist/_chunks/index-mvj9PSKd.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +380 -172
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +380 -173
- package/dist/server/index.mjs.map +1 -1
- package/package.json +22 -15
- package/dist/_chunks/App-0Er6xxcq.mjs.map +0 -1
- package/dist/_chunks/App-C768ulk4.js.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
- package/dist/_chunks/en-WuuhP6Bn.mjs.map +0 -1
- package/dist/_chunks/en-gcJJ5htG.js.map +0 -1
- package/dist/_chunks/index-BLSMpbpZ.js.map +0 -1
- package/dist/_chunks/index-fJx1up7m.mjs.map +0 -1
- package/dist/admin/src/components/CMReleasesContainer.d.ts +0 -1
- package/dist/admin/src/components/RelativeTime.d.ts +0 -28
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +0 -26
- package/dist/admin/src/components/ReleaseActionOptions.d.ts +0 -9
- package/dist/admin/src/components/ReleaseModal.d.ts +0 -16
- package/dist/admin/src/constants.d.ts +0 -58
- package/dist/admin/src/index.d.ts +0 -3
- package/dist/admin/src/pages/App.d.ts +0 -1
- package/dist/admin/src/pages/PurchaseContentReleases.d.ts +0 -2
- package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +0 -2
- package/dist/admin/src/pages/ReleasesPage.d.ts +0 -8
- package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +0 -181
- package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +0 -39
- package/dist/admin/src/pluginId.d.ts +0 -1
- package/dist/admin/src/services/axios.d.ts +0 -29
- package/dist/admin/src/services/release.d.ts +0 -369
- package/dist/admin/src/store/hooks.d.ts +0 -7
- package/dist/admin/src/utils/time.d.ts +0 -1
- package/dist/server/src/bootstrap.d.ts +0 -5
- package/dist/server/src/bootstrap.d.ts.map +0 -1
- package/dist/server/src/constants.d.ts +0 -12
- package/dist/server/src/constants.d.ts.map +0 -1
- package/dist/server/src/content-types/index.d.ts +0 -99
- package/dist/server/src/content-types/index.d.ts.map +0 -1
- package/dist/server/src/content-types/release/index.d.ts +0 -48
- package/dist/server/src/content-types/release/index.d.ts.map +0 -1
- package/dist/server/src/content-types/release/schema.d.ts +0 -47
- package/dist/server/src/content-types/release/schema.d.ts.map +0 -1
- package/dist/server/src/content-types/release-action/index.d.ts +0 -50
- package/dist/server/src/content-types/release-action/index.d.ts.map +0 -1
- package/dist/server/src/content-types/release-action/schema.d.ts +0 -49
- package/dist/server/src/content-types/release-action/schema.d.ts.map +0 -1
- package/dist/server/src/controllers/index.d.ts +0 -18
- package/dist/server/src/controllers/index.d.ts.map +0 -1
- package/dist/server/src/controllers/release-action.d.ts +0 -9
- package/dist/server/src/controllers/release-action.d.ts.map +0 -1
- package/dist/server/src/controllers/release.d.ts +0 -11
- package/dist/server/src/controllers/release.d.ts.map +0 -1
- package/dist/server/src/controllers/validation/release-action.d.ts +0 -3
- package/dist/server/src/controllers/validation/release-action.d.ts.map +0 -1
- package/dist/server/src/controllers/validation/release.d.ts +0 -2
- package/dist/server/src/controllers/validation/release.d.ts.map +0 -1
- package/dist/server/src/destroy.d.ts +0 -5
- package/dist/server/src/destroy.d.ts.map +0 -1
- package/dist/server/src/index.d.ts +0 -3838
- package/dist/server/src/index.d.ts.map +0 -1
- package/dist/server/src/migrations/index.d.ts +0 -10
- package/dist/server/src/migrations/index.d.ts.map +0 -1
- package/dist/server/src/register.d.ts +0 -5
- package/dist/server/src/register.d.ts.map +0 -1
- package/dist/server/src/routes/index.d.ts +0 -35
- package/dist/server/src/routes/index.d.ts.map +0 -1
- package/dist/server/src/routes/release-action.d.ts +0 -18
- package/dist/server/src/routes/release-action.d.ts.map +0 -1
- package/dist/server/src/routes/release.d.ts +0 -18
- package/dist/server/src/routes/release.d.ts.map +0 -1
- package/dist/server/src/services/index.d.ts +0 -3572
- package/dist/server/src/services/index.d.ts.map +0 -1
- package/dist/server/src/services/release.d.ts +0 -1812
- package/dist/server/src/services/release.d.ts.map +0 -1
- package/dist/server/src/services/scheduling.d.ts +0 -18
- package/dist/server/src/services/scheduling.d.ts.map +0 -1
- package/dist/server/src/services/validation.d.ts +0 -14
- package/dist/server/src/services/validation.d.ts.map +0 -1
- package/dist/server/src/utils/index.d.ts +0 -18
- package/dist/server/src/utils/index.d.ts.map +0 -1
- package/dist/shared/contracts/release-actions.d.ts +0 -105
- package/dist/shared/contracts/release-actions.d.ts.map +0 -1
- package/dist/shared/contracts/releases.d.ts +0 -166
- package/dist/shared/contracts/releases.d.ts.map +0 -1
- package/dist/shared/types.d.ts +0 -24
- package/dist/shared/types.d.ts.map +0 -1
- package/dist/shared/validation-schemas.d.ts +0 -2
- package/dist/shared/validation-schemas.d.ts.map +0 -1
package/dist/server/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { contentTypes as contentTypes$1, mapAsync, setCreatorFields, errors, validateYupSchema, yup as yup$1 } from "@strapi/utils";
|
|
2
2
|
import isEqual from "lodash/isEqual";
|
|
3
3
|
import { difference, keys } from "lodash";
|
|
4
4
|
import _ from "lodash/fp";
|
|
5
|
+
import EE from "@strapi/strapi/dist/utils/ee";
|
|
5
6
|
import { scheduleJob } from "node-schedule";
|
|
6
7
|
import * as yup from "yup";
|
|
7
8
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
@@ -76,10 +77,28 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
76
77
|
return false;
|
|
77
78
|
}
|
|
78
79
|
};
|
|
80
|
+
async function deleteActionsOnDisableDraftAndPublish({
|
|
81
|
+
oldContentTypes,
|
|
82
|
+
contentTypes: contentTypes2
|
|
83
|
+
}) {
|
|
84
|
+
if (!oldContentTypes) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
for (const uid in contentTypes2) {
|
|
88
|
+
if (!oldContentTypes[uid]) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const oldContentType = oldContentTypes[uid];
|
|
92
|
+
const contentType = contentTypes2[uid];
|
|
93
|
+
if (contentTypes$1.hasDraftAndPublish(oldContentType) && !contentTypes$1.hasDraftAndPublish(contentType)) {
|
|
94
|
+
await strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: uid }).execute();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
79
98
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
80
99
|
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes2)) ?? [];
|
|
81
100
|
if (deletedContentTypes.length) {
|
|
82
|
-
await
|
|
101
|
+
await mapAsync(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
83
102
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
84
103
|
});
|
|
85
104
|
}
|
|
@@ -98,7 +117,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
98
117
|
}
|
|
99
118
|
}
|
|
100
119
|
});
|
|
101
|
-
|
|
120
|
+
mapAsync(releasesWithoutStatus, async (release2) => {
|
|
102
121
|
const actions = release2.actions;
|
|
103
122
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
104
123
|
for (const action of notValidatedActions) {
|
|
@@ -129,7 +148,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
129
148
|
}
|
|
130
149
|
}
|
|
131
150
|
});
|
|
132
|
-
|
|
151
|
+
mapAsync(publishedReleases, async (release2) => {
|
|
133
152
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
134
153
|
where: {
|
|
135
154
|
id: release2.id
|
|
@@ -142,9 +161,11 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
142
161
|
}
|
|
143
162
|
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
144
163
|
if (oldContentTypes !== void 0 && contentTypes2 !== void 0) {
|
|
145
|
-
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes)
|
|
164
|
+
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes).filter(
|
|
165
|
+
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
166
|
+
);
|
|
146
167
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
147
|
-
|
|
168
|
+
mapAsync(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
148
169
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
149
170
|
const contentType = contentTypes2[contentTypeUID];
|
|
150
171
|
if (!isEqual(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -157,8 +178,8 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
157
178
|
release: true
|
|
158
179
|
}
|
|
159
180
|
});
|
|
160
|
-
await
|
|
161
|
-
if (action.entry) {
|
|
181
|
+
await mapAsync(actions, async (action) => {
|
|
182
|
+
if (action.entry && action.release) {
|
|
162
183
|
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
163
184
|
strapi
|
|
164
185
|
});
|
|
@@ -180,21 +201,77 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
180
201
|
});
|
|
181
202
|
}
|
|
182
203
|
}).then(() => {
|
|
183
|
-
|
|
204
|
+
mapAsync(releasesAffected, async (releaseId) => {
|
|
184
205
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
185
206
|
});
|
|
186
207
|
});
|
|
187
208
|
}
|
|
188
209
|
}
|
|
210
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
211
|
+
if (!oldContentTypes) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
215
|
+
if (!i18nPlugin) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
for (const uid in contentTypes2) {
|
|
219
|
+
if (!oldContentTypes[uid]) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const oldContentType = oldContentTypes[uid];
|
|
223
|
+
const contentType = contentTypes2[uid];
|
|
224
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
225
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
226
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
227
|
+
locale: null
|
|
228
|
+
}).where({ contentType: uid }).execute();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
233
|
+
if (!oldContentTypes) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
237
|
+
if (!i18nPlugin) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
for (const uid in contentTypes2) {
|
|
241
|
+
if (!oldContentTypes[uid]) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const oldContentType = oldContentTypes[uid];
|
|
245
|
+
const contentType = contentTypes2[uid];
|
|
246
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
247
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
248
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
249
|
+
const defaultLocale = await getDefaultLocale();
|
|
250
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
251
|
+
locale: defaultLocale
|
|
252
|
+
}).where({ contentType: uid }).execute();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
|
|
189
257
|
const register = async ({ strapi: strapi2 }) => {
|
|
190
|
-
if (
|
|
258
|
+
if (features$2.isEnabled("cms-content-releases")) {
|
|
191
259
|
await strapi2.admin.services.permission.actionProvider.registerMany(ACTIONS);
|
|
192
|
-
strapi2.hook("strapi::content-types.
|
|
260
|
+
strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish).register(disableContentTypeLocalized);
|
|
261
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
262
|
+
}
|
|
263
|
+
if (strapi2.plugin("graphql")) {
|
|
264
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
265
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
266
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
193
267
|
}
|
|
194
268
|
};
|
|
269
|
+
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
195
270
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
196
|
-
if (
|
|
197
|
-
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes)
|
|
271
|
+
if (features$1.isEnabled("cms-content-releases")) {
|
|
272
|
+
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
273
|
+
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
274
|
+
);
|
|
198
275
|
strapi2.db.lifecycles.subscribe({
|
|
199
276
|
models: contentTypesWithDraftAndPublish,
|
|
200
277
|
async afterDelete(event) {
|
|
@@ -230,7 +307,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
230
307
|
*/
|
|
231
308
|
async beforeDeleteMany(event) {
|
|
232
309
|
const { model, params } = event;
|
|
233
|
-
if (model.kind === "collectionType") {
|
|
310
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
234
311
|
const { where } = params;
|
|
235
312
|
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
236
313
|
event.state.entriesToDelete = entriesToDelete;
|
|
@@ -312,27 +389,23 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
312
389
|
}
|
|
313
390
|
}
|
|
314
391
|
});
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
});
|
|
325
|
-
}
|
|
392
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
393
|
+
strapi2.log.error(
|
|
394
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
395
|
+
);
|
|
396
|
+
throw err;
|
|
397
|
+
});
|
|
398
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
399
|
+
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
400
|
+
});
|
|
326
401
|
}
|
|
327
402
|
};
|
|
328
403
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
job.cancel();
|
|
335
|
-
}
|
|
404
|
+
const scheduledJobs = getService("scheduling", {
|
|
405
|
+
strapi: strapi2
|
|
406
|
+
}).getAll();
|
|
407
|
+
for (const [, job] of scheduledJobs) {
|
|
408
|
+
job.cancel();
|
|
336
409
|
}
|
|
337
410
|
};
|
|
338
411
|
const schema$1 = {
|
|
@@ -457,6 +530,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
457
530
|
release: release2
|
|
458
531
|
});
|
|
459
532
|
};
|
|
533
|
+
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
534
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
535
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
536
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
537
|
+
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
538
|
+
try {
|
|
539
|
+
if (actionType === "publish") {
|
|
540
|
+
await entityManagerService.publish(entry, uid);
|
|
541
|
+
} else {
|
|
542
|
+
await entityManagerService.unpublish(entry, uid);
|
|
543
|
+
}
|
|
544
|
+
} catch (error) {
|
|
545
|
+
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
546
|
+
;
|
|
547
|
+
else {
|
|
548
|
+
throw error;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
553
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
554
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
555
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
556
|
+
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
557
|
+
filters: {
|
|
558
|
+
id: {
|
|
559
|
+
$in: entriesToPublishIds
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
populate
|
|
563
|
+
});
|
|
564
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
565
|
+
filters: {
|
|
566
|
+
id: {
|
|
567
|
+
$in: entriestoUnpublishIds
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
populate
|
|
571
|
+
});
|
|
572
|
+
if (entriesToPublish.length > 0) {
|
|
573
|
+
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
574
|
+
}
|
|
575
|
+
if (entriesToUnpublish.length > 0) {
|
|
576
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
const getFormattedActions = async (releaseId) => {
|
|
580
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
581
|
+
where: {
|
|
582
|
+
release: {
|
|
583
|
+
id: releaseId
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
populate: {
|
|
587
|
+
entry: {
|
|
588
|
+
fields: ["id"]
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
if (actions.length === 0) {
|
|
593
|
+
throw new errors.ValidationError("No entries to publish");
|
|
594
|
+
}
|
|
595
|
+
const collectionTypeActions = {};
|
|
596
|
+
const singleTypeActions = [];
|
|
597
|
+
for (const action of actions) {
|
|
598
|
+
const contentTypeUid = action.contentType;
|
|
599
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
600
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
601
|
+
collectionTypeActions[contentTypeUid] = {
|
|
602
|
+
entriesToPublishIds: [],
|
|
603
|
+
entriesToUnpublishIds: []
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
if (action.type === "publish") {
|
|
607
|
+
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
608
|
+
} else {
|
|
609
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
610
|
+
}
|
|
611
|
+
} else {
|
|
612
|
+
singleTypeActions.push({
|
|
613
|
+
uid: contentTypeUid,
|
|
614
|
+
action: action.type,
|
|
615
|
+
id: action.entry.id
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return { collectionTypeActions, singleTypeActions };
|
|
620
|
+
};
|
|
460
621
|
return {
|
|
461
622
|
async create(releaseData, { user }) {
|
|
462
623
|
const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
|
|
@@ -476,7 +637,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
476
637
|
status: "empty"
|
|
477
638
|
}
|
|
478
639
|
});
|
|
479
|
-
if (
|
|
640
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
480
641
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
481
642
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
482
643
|
}
|
|
@@ -500,12 +661,18 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
500
661
|
}
|
|
501
662
|
});
|
|
502
663
|
},
|
|
503
|
-
async findManyWithContentTypeEntryAttached(contentTypeUid,
|
|
664
|
+
async findManyWithContentTypeEntryAttached(contentTypeUid, entriesIds) {
|
|
665
|
+
let entries = entriesIds;
|
|
666
|
+
if (!Array.isArray(entriesIds)) {
|
|
667
|
+
entries = [entriesIds];
|
|
668
|
+
}
|
|
504
669
|
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
505
670
|
where: {
|
|
506
671
|
actions: {
|
|
507
672
|
target_type: contentTypeUid,
|
|
508
|
-
target_id:
|
|
673
|
+
target_id: {
|
|
674
|
+
$in: entries
|
|
675
|
+
}
|
|
509
676
|
},
|
|
510
677
|
releasedAt: {
|
|
511
678
|
$null: true
|
|
@@ -516,18 +683,25 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
516
683
|
actions: {
|
|
517
684
|
where: {
|
|
518
685
|
target_type: contentTypeUid,
|
|
519
|
-
target_id:
|
|
686
|
+
target_id: {
|
|
687
|
+
$in: entries
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
populate: {
|
|
691
|
+
entry: {
|
|
692
|
+
select: ["id"]
|
|
693
|
+
}
|
|
520
694
|
}
|
|
521
695
|
}
|
|
522
696
|
}
|
|
523
697
|
});
|
|
524
698
|
return releases.map((release2) => {
|
|
525
699
|
if (release2.actions?.length) {
|
|
526
|
-
const
|
|
700
|
+
const actionsForEntry = release2.actions;
|
|
527
701
|
delete release2.actions;
|
|
528
702
|
return {
|
|
529
703
|
...release2,
|
|
530
|
-
|
|
704
|
+
actions: actionsForEntry
|
|
531
705
|
};
|
|
532
706
|
}
|
|
533
707
|
return release2;
|
|
@@ -601,13 +775,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
601
775
|
// @ts-expect-error see above
|
|
602
776
|
data: releaseWithCreatorFields
|
|
603
777
|
});
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
schedulingService.cancel(id);
|
|
610
|
-
}
|
|
778
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
779
|
+
if (releaseData.scheduledAt) {
|
|
780
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
781
|
+
} else if (release2.scheduledAt) {
|
|
782
|
+
schedulingService.cancel(id);
|
|
611
783
|
}
|
|
612
784
|
this.updateReleaseStatus(id);
|
|
613
785
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
@@ -773,7 +945,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
773
945
|
});
|
|
774
946
|
await strapi2.entityService.delete(RELEASE_MODEL_UID, releaseId);
|
|
775
947
|
});
|
|
776
|
-
if (
|
|
948
|
+
if (release2.scheduledAt) {
|
|
777
949
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
778
950
|
await schedulingService.cancel(release2.id);
|
|
779
951
|
}
|
|
@@ -781,145 +953,71 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
781
953
|
return release2;
|
|
782
954
|
},
|
|
783
955
|
async publish(releaseId) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
actions: {
|
|
791
|
-
populate: {
|
|
792
|
-
entry: {
|
|
793
|
-
fields: ["id"]
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
);
|
|
800
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
956
|
+
const {
|
|
957
|
+
release: release2,
|
|
958
|
+
error
|
|
959
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
960
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
961
|
+
if (!lockedRelease) {
|
|
801
962
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
802
963
|
}
|
|
803
|
-
if (
|
|
964
|
+
if (lockedRelease.releasedAt) {
|
|
804
965
|
throw new errors.ValidationError("Release already published");
|
|
805
966
|
}
|
|
806
|
-
if (
|
|
807
|
-
throw new errors.ValidationError("
|
|
967
|
+
if (lockedRelease.status === "failed") {
|
|
968
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
808
969
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
entriesToUnpublishIds: []
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
if (action.type === "publish") {
|
|
821
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
822
|
-
} else {
|
|
823
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
824
|
-
}
|
|
825
|
-
} else {
|
|
826
|
-
singleTypeActions.push({
|
|
827
|
-
uid: contentTypeUid,
|
|
828
|
-
action: action.type,
|
|
829
|
-
id: action.entry.id
|
|
830
|
-
});
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
834
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
835
|
-
await strapi2.db.transaction(async () => {
|
|
836
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
837
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
838
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
839
|
-
try {
|
|
840
|
-
if (action === "publish") {
|
|
841
|
-
await entityManagerService.publish(entry, uid);
|
|
842
|
-
} else {
|
|
843
|
-
await entityManagerService.unpublish(entry, uid);
|
|
844
|
-
}
|
|
845
|
-
} catch (error) {
|
|
846
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
847
|
-
} else {
|
|
848
|
-
throw error;
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
853
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
854
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
855
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
856
|
-
contentTypeUid,
|
|
857
|
-
{
|
|
858
|
-
filters: {
|
|
859
|
-
id: {
|
|
860
|
-
$in: entriestoPublishIds
|
|
861
|
-
}
|
|
862
|
-
},
|
|
863
|
-
populate
|
|
864
|
-
}
|
|
865
|
-
);
|
|
866
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
867
|
-
contentTypeUid,
|
|
868
|
-
{
|
|
869
|
-
filters: {
|
|
870
|
-
id: {
|
|
871
|
-
$in: entriesToUnpublishIds
|
|
872
|
-
}
|
|
873
|
-
},
|
|
874
|
-
populate
|
|
875
|
-
}
|
|
876
|
-
);
|
|
877
|
-
if (entriesToPublish.length > 0) {
|
|
878
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
970
|
+
try {
|
|
971
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
972
|
+
const { collectionTypeActions, singleTypeActions } = await getFormattedActions(
|
|
973
|
+
releaseId
|
|
974
|
+
);
|
|
975
|
+
await strapi2.db.transaction(async () => {
|
|
976
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
977
|
+
await publishSingleTypeAction(uid, action, id);
|
|
879
978
|
}
|
|
880
|
-
|
|
881
|
-
|
|
979
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
980
|
+
const uid = contentTypeUid;
|
|
981
|
+
await publishCollectionTypeAction(
|
|
982
|
+
uid,
|
|
983
|
+
collectionTypeActions[uid].entriesToPublishIds,
|
|
984
|
+
collectionTypeActions[uid].entriesToUnpublishIds
|
|
985
|
+
);
|
|
882
986
|
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
892
|
-
},
|
|
893
|
-
populate: {
|
|
894
|
-
actions: {
|
|
895
|
-
// @ts-expect-error is not expecting count but it is working
|
|
896
|
-
count: true
|
|
987
|
+
});
|
|
988
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
989
|
+
where: {
|
|
990
|
+
id: releaseId
|
|
991
|
+
},
|
|
992
|
+
data: {
|
|
993
|
+
status: "done",
|
|
994
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
897
995
|
}
|
|
898
|
-
}
|
|
899
|
-
});
|
|
900
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
996
|
+
});
|
|
901
997
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
902
998
|
isPublished: true,
|
|
903
|
-
release:
|
|
999
|
+
release: release22
|
|
904
1000
|
});
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
} catch (error) {
|
|
909
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
1001
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
1002
|
+
return { release: release22, error: null };
|
|
1003
|
+
} catch (error2) {
|
|
910
1004
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
911
1005
|
isPublished: false,
|
|
912
|
-
error
|
|
1006
|
+
error: error2
|
|
913
1007
|
});
|
|
914
|
-
|
|
915
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
916
|
-
where: { id: releaseId },
|
|
917
|
-
data: {
|
|
1008
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
918
1009
|
status: "failed"
|
|
919
|
-
}
|
|
920
|
-
|
|
1010
|
+
}).transacting(trx).execute();
|
|
1011
|
+
return {
|
|
1012
|
+
release: null,
|
|
1013
|
+
error: error2
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
if (error) {
|
|
921
1018
|
throw error;
|
|
922
1019
|
}
|
|
1020
|
+
return release2;
|
|
923
1021
|
},
|
|
924
1022
|
async updateAction(actionId, releaseId, update) {
|
|
925
1023
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -1006,6 +1104,12 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1006
1104
|
}
|
|
1007
1105
|
};
|
|
1008
1106
|
};
|
|
1107
|
+
class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
1108
|
+
constructor(message) {
|
|
1109
|
+
super(message);
|
|
1110
|
+
this.name = "AlreadyOnReleaseError";
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1009
1113
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1010
1114
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1011
1115
|
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
@@ -1018,7 +1122,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1018
1122
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1019
1123
|
);
|
|
1020
1124
|
if (isEntryInRelease) {
|
|
1021
|
-
throw new
|
|
1125
|
+
throw new AlreadyOnReleaseError(
|
|
1022
1126
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1023
1127
|
);
|
|
1024
1128
|
}
|
|
@@ -1028,9 +1132,17 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1028
1132
|
if (!contentType) {
|
|
1029
1133
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1030
1134
|
}
|
|
1135
|
+
if (!contentType.options?.draftAndPublish) {
|
|
1136
|
+
throw new errors.ValidationError(
|
|
1137
|
+
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1031
1140
|
},
|
|
1032
1141
|
async validatePendingReleasesLimit() {
|
|
1033
|
-
const maximumPendingReleases =
|
|
1142
|
+
const maximumPendingReleases = (
|
|
1143
|
+
// @ts-expect-error - options is not typed into features
|
|
1144
|
+
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1145
|
+
);
|
|
1034
1146
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1035
1147
|
filters: {
|
|
1036
1148
|
releasedAt: {
|
|
@@ -1118,7 +1230,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1118
1230
|
const services = {
|
|
1119
1231
|
release: createReleaseService,
|
|
1120
1232
|
"release-validation": createReleaseValidationService,
|
|
1121
|
-
|
|
1233
|
+
scheduling: createSchedulingService
|
|
1122
1234
|
};
|
|
1123
1235
|
const RELEASE_SCHEMA = yup.object().shape({
|
|
1124
1236
|
name: yup.string().trim().required(),
|
|
@@ -1205,6 +1317,33 @@ const releaseController = {
|
|
|
1205
1317
|
};
|
|
1206
1318
|
ctx.body = { data };
|
|
1207
1319
|
},
|
|
1320
|
+
async mapEntriesToReleases(ctx) {
|
|
1321
|
+
const { contentTypeUid, entriesIds } = ctx.query;
|
|
1322
|
+
if (!contentTypeUid || !entriesIds) {
|
|
1323
|
+
throw new errors.ValidationError("Missing required query parameters");
|
|
1324
|
+
}
|
|
1325
|
+
const releaseService = getService("release", { strapi });
|
|
1326
|
+
const releasesWithActions = await releaseService.findManyWithContentTypeEntryAttached(
|
|
1327
|
+
contentTypeUid,
|
|
1328
|
+
entriesIds
|
|
1329
|
+
);
|
|
1330
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1331
|
+
(acc, release2) => {
|
|
1332
|
+
release2.actions.forEach((action) => {
|
|
1333
|
+
if (!acc[action.entry.id]) {
|
|
1334
|
+
acc[action.entry.id] = [{ id: release2.id, name: release2.name }];
|
|
1335
|
+
} else {
|
|
1336
|
+
acc[action.entry.id].push({ id: release2.id, name: release2.name });
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1339
|
+
return acc;
|
|
1340
|
+
},
|
|
1341
|
+
{}
|
|
1342
|
+
);
|
|
1343
|
+
ctx.body = {
|
|
1344
|
+
data: mappedEntriesInReleases
|
|
1345
|
+
};
|
|
1346
|
+
},
|
|
1208
1347
|
async create(ctx) {
|
|
1209
1348
|
const user = ctx.state.user;
|
|
1210
1349
|
const releaseArgs = ctx.request.body;
|
|
@@ -1294,6 +1433,38 @@ const releaseActionController = {
|
|
|
1294
1433
|
data: releaseAction2
|
|
1295
1434
|
};
|
|
1296
1435
|
},
|
|
1436
|
+
async createMany(ctx) {
|
|
1437
|
+
const releaseId = ctx.params.releaseId;
|
|
1438
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1439
|
+
await Promise.all(
|
|
1440
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1441
|
+
);
|
|
1442
|
+
const releaseService = getService("release", { strapi });
|
|
1443
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1444
|
+
const releaseActions2 = await Promise.all(
|
|
1445
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1446
|
+
try {
|
|
1447
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1448
|
+
return action;
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1451
|
+
return null;
|
|
1452
|
+
}
|
|
1453
|
+
throw error;
|
|
1454
|
+
}
|
|
1455
|
+
})
|
|
1456
|
+
);
|
|
1457
|
+
return releaseActions2;
|
|
1458
|
+
});
|
|
1459
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1460
|
+
ctx.body = {
|
|
1461
|
+
data: newReleaseActions,
|
|
1462
|
+
meta: {
|
|
1463
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1464
|
+
totalEntries: releaseActions.length
|
|
1465
|
+
}
|
|
1466
|
+
};
|
|
1467
|
+
},
|
|
1297
1468
|
async findMany(ctx) {
|
|
1298
1469
|
const releaseId = ctx.params.releaseId;
|
|
1299
1470
|
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
@@ -1317,7 +1488,7 @@ const releaseActionController = {
|
|
|
1317
1488
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1318
1489
|
return acc;
|
|
1319
1490
|
}, {});
|
|
1320
|
-
const sanitizedResults = await
|
|
1491
|
+
const sanitizedResults = await mapAsync(results, async (action) => ({
|
|
1321
1492
|
...action,
|
|
1322
1493
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1323
1494
|
}));
|
|
@@ -1362,6 +1533,22 @@ const controllers = { release: releaseController, "release-action": releaseActio
|
|
|
1362
1533
|
const release = {
|
|
1363
1534
|
type: "admin",
|
|
1364
1535
|
routes: [
|
|
1536
|
+
{
|
|
1537
|
+
method: "GET",
|
|
1538
|
+
path: "/mapEntriesToReleases",
|
|
1539
|
+
handler: "release.mapEntriesToReleases",
|
|
1540
|
+
config: {
|
|
1541
|
+
policies: [
|
|
1542
|
+
"admin::isAuthenticatedAdmin",
|
|
1543
|
+
{
|
|
1544
|
+
name: "admin::hasPermissions",
|
|
1545
|
+
config: {
|
|
1546
|
+
actions: ["plugin::content-releases.read"]
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
]
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1365
1552
|
{
|
|
1366
1553
|
method: "POST",
|
|
1367
1554
|
path: "/",
|
|
@@ -1479,6 +1666,22 @@ const releaseAction = {
|
|
|
1479
1666
|
]
|
|
1480
1667
|
}
|
|
1481
1668
|
},
|
|
1669
|
+
{
|
|
1670
|
+
method: "POST",
|
|
1671
|
+
path: "/:releaseId/actions/bulk",
|
|
1672
|
+
handler: "release-action.createMany",
|
|
1673
|
+
config: {
|
|
1674
|
+
policies: [
|
|
1675
|
+
"admin::isAuthenticatedAdmin",
|
|
1676
|
+
{
|
|
1677
|
+
name: "admin::hasPermissions",
|
|
1678
|
+
config: {
|
|
1679
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
]
|
|
1683
|
+
}
|
|
1684
|
+
},
|
|
1482
1685
|
{
|
|
1483
1686
|
method: "GET",
|
|
1484
1687
|
path: "/:releaseId/actions",
|
|
@@ -1533,8 +1736,9 @@ const routes = {
|
|
|
1533
1736
|
release,
|
|
1534
1737
|
"release-action": releaseAction
|
|
1535
1738
|
};
|
|
1739
|
+
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1536
1740
|
const getPlugin = () => {
|
|
1537
|
-
if (
|
|
1741
|
+
if (features.isEnabled("cms-content-releases")) {
|
|
1538
1742
|
return {
|
|
1539
1743
|
register,
|
|
1540
1744
|
bootstrap,
|
|
@@ -1546,6 +1750,9 @@ const getPlugin = () => {
|
|
|
1546
1750
|
};
|
|
1547
1751
|
}
|
|
1548
1752
|
return {
|
|
1753
|
+
// Always return register, it handles its own feature check
|
|
1754
|
+
register,
|
|
1755
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1549
1756
|
contentTypes
|
|
1550
1757
|
};
|
|
1551
1758
|
};
|