@strapi/content-releases 0.0.0-experimental.e3e48deb89bd0a1b6cc69b698696566fa7854a95 → 0.0.0-experimental.e5740babedd53cf5b6af99d74920b6b9ef1e4c11
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-PQlYzNfb.mjs → App-HVXzE3i3.mjs} +256 -280
- package/dist/_chunks/App-HVXzE3i3.mjs.map +1 -0
- package/dist/_chunks/{App-lzeJz92X.js → App-l62gIUTX.js} +254 -278
- package/dist/_chunks/App-l62gIUTX.js.map +1 -0
- package/dist/_chunks/{en-WuuhP6Bn.mjs → en-RdapH-9X.mjs} +1 -2
- package/dist/_chunks/en-RdapH-9X.mjs.map +1 -0
- package/dist/_chunks/{en-gcJJ5htG.js → en-faJDuv3q.js} +1 -2
- package/dist/_chunks/en-faJDuv3q.js.map +1 -0
- package/dist/_chunks/{index-Nf1JfI-m.js → index-ML_b3php.js} +28 -22
- package/dist/_chunks/index-ML_b3php.js.map +1 -0
- package/dist/_chunks/{index--4AgLDzb.mjs → index-Ys87ROOe.mjs} +32 -26
- package/dist/_chunks/index-Ys87ROOe.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +344 -203
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +344 -204
- package/dist/server/index.mjs.map +1 -1
- package/package.json +21 -14
- package/dist/_chunks/App-PQlYzNfb.mjs.map +0 -1
- package/dist/_chunks/App-lzeJz92X.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--4AgLDzb.mjs.map +0 -1
- package/dist/_chunks/index-Nf1JfI-m.js.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 -2092
- 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 -1826
- package/dist/server/src/services/index.d.ts.map +0 -1
- package/dist/server/src/services/release.d.ts +0 -66
- 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 -14
- 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";
|
|
@@ -59,10 +60,7 @@ const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
|
59
60
|
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
60
61
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
61
62
|
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
62
|
-
const entry = await strapi2.
|
|
63
|
-
where: { id: entryId },
|
|
64
|
-
populate
|
|
65
|
-
});
|
|
63
|
+
const entry = await strapi2.entityService.findOne(contentTypeUid, entryId, { populate });
|
|
66
64
|
return entry;
|
|
67
65
|
};
|
|
68
66
|
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
@@ -79,10 +77,28 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
79
77
|
return false;
|
|
80
78
|
}
|
|
81
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
|
+
}
|
|
82
98
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
83
99
|
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes2)) ?? [];
|
|
84
100
|
if (deletedContentTypes.length) {
|
|
85
|
-
await
|
|
101
|
+
await mapAsync(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
86
102
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
87
103
|
});
|
|
88
104
|
}
|
|
@@ -101,7 +117,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
101
117
|
}
|
|
102
118
|
}
|
|
103
119
|
});
|
|
104
|
-
|
|
120
|
+
mapAsync(releasesWithoutStatus, async (release2) => {
|
|
105
121
|
const actions = release2.actions;
|
|
106
122
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
107
123
|
for (const action of notValidatedActions) {
|
|
@@ -132,7 +148,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
132
148
|
}
|
|
133
149
|
}
|
|
134
150
|
});
|
|
135
|
-
|
|
151
|
+
mapAsync(publishedReleases, async (release2) => {
|
|
136
152
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
137
153
|
where: {
|
|
138
154
|
id: release2.id
|
|
@@ -145,9 +161,11 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
145
161
|
}
|
|
146
162
|
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
147
163
|
if (oldContentTypes !== void 0 && contentTypes2 !== void 0) {
|
|
148
|
-
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes)
|
|
164
|
+
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes).filter(
|
|
165
|
+
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
166
|
+
);
|
|
149
167
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
150
|
-
|
|
168
|
+
mapAsync(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
151
169
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
152
170
|
const contentType = contentTypes2[contentTypeUID];
|
|
153
171
|
if (!isEqual(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -160,8 +178,8 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
160
178
|
release: true
|
|
161
179
|
}
|
|
162
180
|
});
|
|
163
|
-
await
|
|
164
|
-
if (action.entry) {
|
|
181
|
+
await mapAsync(actions, async (action) => {
|
|
182
|
+
if (action.entry && action.release) {
|
|
165
183
|
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
166
184
|
strapi
|
|
167
185
|
});
|
|
@@ -183,21 +201,71 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
183
201
|
});
|
|
184
202
|
}
|
|
185
203
|
}).then(() => {
|
|
186
|
-
|
|
204
|
+
mapAsync(releasesAffected, async (releaseId) => {
|
|
187
205
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
188
206
|
});
|
|
189
207
|
});
|
|
190
208
|
}
|
|
191
209
|
}
|
|
210
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
211
|
+
if (!oldContentTypes) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
for (const uid in contentTypes2) {
|
|
215
|
+
if (!oldContentTypes[uid]) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const oldContentType = oldContentTypes[uid];
|
|
219
|
+
const contentType = contentTypes2[uid];
|
|
220
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
221
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
222
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
223
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
224
|
+
locale: null
|
|
225
|
+
}).where({ contentType: uid }).execute();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
230
|
+
if (!oldContentTypes) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
for (const uid in contentTypes2) {
|
|
234
|
+
if (!oldContentTypes[uid]) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const oldContentType = oldContentTypes[uid];
|
|
238
|
+
const contentType = contentTypes2[uid];
|
|
239
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
240
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
241
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
242
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
243
|
+
const defaultLocale = await getDefaultLocale();
|
|
244
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
245
|
+
locale: defaultLocale
|
|
246
|
+
}).where({ contentType: uid }).execute();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
|
|
192
251
|
const register = async ({ strapi: strapi2 }) => {
|
|
193
|
-
if (
|
|
252
|
+
if (features$2.isEnabled("cms-content-releases")) {
|
|
194
253
|
await strapi2.admin.services.permission.actionProvider.registerMany(ACTIONS);
|
|
195
|
-
strapi2.hook("strapi::content-types.
|
|
254
|
+
strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish).register(disableContentTypeLocalized);
|
|
255
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
256
|
+
}
|
|
257
|
+
if (strapi2.plugin("graphql")) {
|
|
258
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
259
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
260
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
196
261
|
}
|
|
197
262
|
};
|
|
263
|
+
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
198
264
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
199
|
-
if (
|
|
200
|
-
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes)
|
|
265
|
+
if (features$1.isEnabled("cms-content-releases")) {
|
|
266
|
+
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
267
|
+
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
268
|
+
);
|
|
201
269
|
strapi2.db.lifecycles.subscribe({
|
|
202
270
|
models: contentTypesWithDraftAndPublish,
|
|
203
271
|
async afterDelete(event) {
|
|
@@ -233,7 +301,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
233
301
|
*/
|
|
234
302
|
async beforeDeleteMany(event) {
|
|
235
303
|
const { model, params } = event;
|
|
236
|
-
if (model.kind === "collectionType") {
|
|
304
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
237
305
|
const { where } = params;
|
|
238
306
|
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
239
307
|
event.state.entriesToDelete = entriesToDelete;
|
|
@@ -315,27 +383,23 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
315
383
|
}
|
|
316
384
|
}
|
|
317
385
|
});
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
});
|
|
328
|
-
}
|
|
386
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
387
|
+
strapi2.log.error(
|
|
388
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
389
|
+
);
|
|
390
|
+
throw err;
|
|
391
|
+
});
|
|
392
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
393
|
+
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
394
|
+
});
|
|
329
395
|
}
|
|
330
396
|
};
|
|
331
397
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
job.cancel();
|
|
338
|
-
}
|
|
398
|
+
const scheduledJobs = getService("scheduling", {
|
|
399
|
+
strapi: strapi2
|
|
400
|
+
}).getAll();
|
|
401
|
+
for (const [, job] of scheduledJobs) {
|
|
402
|
+
job.cancel();
|
|
339
403
|
}
|
|
340
404
|
};
|
|
341
405
|
const schema$1 = {
|
|
@@ -460,6 +524,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
460
524
|
release: release2
|
|
461
525
|
});
|
|
462
526
|
};
|
|
527
|
+
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
528
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
529
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
530
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
531
|
+
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
532
|
+
try {
|
|
533
|
+
if (actionType === "publish") {
|
|
534
|
+
await entityManagerService.publish(entry, uid);
|
|
535
|
+
} else {
|
|
536
|
+
await entityManagerService.unpublish(entry, uid);
|
|
537
|
+
}
|
|
538
|
+
} catch (error) {
|
|
539
|
+
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
540
|
+
;
|
|
541
|
+
else {
|
|
542
|
+
throw error;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
547
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
548
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
549
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
550
|
+
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
551
|
+
filters: {
|
|
552
|
+
id: {
|
|
553
|
+
$in: entriesToPublishIds
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
populate
|
|
557
|
+
});
|
|
558
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
559
|
+
filters: {
|
|
560
|
+
id: {
|
|
561
|
+
$in: entriestoUnpublishIds
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
populate
|
|
565
|
+
});
|
|
566
|
+
if (entriesToPublish.length > 0) {
|
|
567
|
+
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
568
|
+
}
|
|
569
|
+
if (entriesToUnpublish.length > 0) {
|
|
570
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
const getFormattedActions = async (releaseId) => {
|
|
574
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
575
|
+
where: {
|
|
576
|
+
release: {
|
|
577
|
+
id: releaseId
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
populate: {
|
|
581
|
+
entry: {
|
|
582
|
+
fields: ["id"]
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
if (actions.length === 0) {
|
|
587
|
+
throw new errors.ValidationError("No entries to publish");
|
|
588
|
+
}
|
|
589
|
+
const collectionTypeActions = {};
|
|
590
|
+
const singleTypeActions = [];
|
|
591
|
+
for (const action of actions) {
|
|
592
|
+
const contentTypeUid = action.contentType;
|
|
593
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
594
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
595
|
+
collectionTypeActions[contentTypeUid] = {
|
|
596
|
+
entriesToPublishIds: [],
|
|
597
|
+
entriesToUnpublishIds: []
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
if (action.type === "publish") {
|
|
601
|
+
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
602
|
+
} else {
|
|
603
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
604
|
+
}
|
|
605
|
+
} else {
|
|
606
|
+
singleTypeActions.push({
|
|
607
|
+
uid: contentTypeUid,
|
|
608
|
+
action: action.type,
|
|
609
|
+
id: action.entry.id
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return { collectionTypeActions, singleTypeActions };
|
|
614
|
+
};
|
|
463
615
|
return {
|
|
464
616
|
async create(releaseData, { user }) {
|
|
465
617
|
const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
|
|
@@ -473,13 +625,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
473
625
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
474
626
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
475
627
|
]);
|
|
476
|
-
const release2 = await strapi2.
|
|
628
|
+
const release2 = await strapi2.entityService.create(RELEASE_MODEL_UID, {
|
|
477
629
|
data: {
|
|
478
630
|
...releaseWithCreatorFields,
|
|
479
631
|
status: "empty"
|
|
480
632
|
}
|
|
481
633
|
});
|
|
482
|
-
if (
|
|
634
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
483
635
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
484
636
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
485
637
|
}
|
|
@@ -487,19 +639,17 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
487
639
|
return release2;
|
|
488
640
|
},
|
|
489
641
|
async findOne(id, query = {}) {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
...dbQuery,
|
|
493
|
-
where: { id }
|
|
642
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, id, {
|
|
643
|
+
...query
|
|
494
644
|
});
|
|
495
645
|
return release2;
|
|
496
646
|
},
|
|
497
647
|
findPage(query) {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
...dbQuery,
|
|
648
|
+
return strapi2.entityService.findPage(RELEASE_MODEL_UID, {
|
|
649
|
+
...query,
|
|
501
650
|
populate: {
|
|
502
651
|
actions: {
|
|
652
|
+
// @ts-expect-error Ignore missing properties
|
|
503
653
|
count: true
|
|
504
654
|
}
|
|
505
655
|
}
|
|
@@ -591,24 +741,26 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
591
741
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
592
742
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
593
743
|
]);
|
|
594
|
-
const release2 = await strapi2.
|
|
744
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, id);
|
|
595
745
|
if (!release2) {
|
|
596
746
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
597
747
|
}
|
|
598
748
|
if (release2.releasedAt) {
|
|
599
749
|
throw new errors.ValidationError("Release already published");
|
|
600
750
|
}
|
|
601
|
-
const updatedRelease = await strapi2.
|
|
602
|
-
|
|
751
|
+
const updatedRelease = await strapi2.entityService.update(RELEASE_MODEL_UID, id, {
|
|
752
|
+
/*
|
|
753
|
+
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
754
|
+
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
755
|
+
*/
|
|
756
|
+
// @ts-expect-error see above
|
|
603
757
|
data: releaseWithCreatorFields
|
|
604
758
|
});
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
schedulingService.cancel(id);
|
|
611
|
-
}
|
|
759
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
760
|
+
if (releaseData.scheduledAt) {
|
|
761
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
762
|
+
} else if (release2.scheduledAt) {
|
|
763
|
+
schedulingService.cancel(id);
|
|
612
764
|
}
|
|
613
765
|
this.updateReleaseStatus(id);
|
|
614
766
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
@@ -622,7 +774,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
622
774
|
validateEntryContentType(action.entry.contentType),
|
|
623
775
|
validateUniqueEntry(releaseId, action)
|
|
624
776
|
]);
|
|
625
|
-
const release2 = await strapi2.
|
|
777
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
626
778
|
if (!release2) {
|
|
627
779
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
628
780
|
}
|
|
@@ -632,7 +784,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
632
784
|
const { entry, type } = action;
|
|
633
785
|
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
634
786
|
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
635
|
-
const releaseAction2 = await strapi2.
|
|
787
|
+
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
636
788
|
data: {
|
|
637
789
|
type,
|
|
638
790
|
contentType: entry.contentType,
|
|
@@ -645,41 +797,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
645
797
|
},
|
|
646
798
|
release: releaseId
|
|
647
799
|
},
|
|
648
|
-
populate: { release: {
|
|
800
|
+
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
649
801
|
});
|
|
650
802
|
this.updateReleaseStatus(releaseId);
|
|
651
803
|
return releaseAction2;
|
|
652
804
|
},
|
|
653
805
|
async findActions(releaseId, query) {
|
|
654
|
-
const release2 = await strapi2.
|
|
655
|
-
|
|
656
|
-
select: ["id"]
|
|
806
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
807
|
+
fields: ["id"]
|
|
657
808
|
});
|
|
658
809
|
if (!release2) {
|
|
659
810
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
660
811
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
query ?? {}
|
|
664
|
-
);
|
|
665
|
-
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
666
|
-
...dbQuery,
|
|
812
|
+
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
813
|
+
...query,
|
|
667
814
|
populate: {
|
|
668
815
|
entry: {
|
|
669
816
|
populate: "*"
|
|
670
817
|
}
|
|
671
818
|
},
|
|
672
|
-
|
|
819
|
+
filters: {
|
|
673
820
|
release: releaseId
|
|
674
821
|
}
|
|
675
822
|
});
|
|
676
823
|
},
|
|
677
824
|
async countActions(query) {
|
|
678
|
-
|
|
679
|
-
RELEASE_ACTION_MODEL_UID,
|
|
680
|
-
query ?? {}
|
|
681
|
-
);
|
|
682
|
-
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
825
|
+
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
683
826
|
},
|
|
684
827
|
async groupActions(actions, groupBy) {
|
|
685
828
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -760,11 +903,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
760
903
|
return componentsMap;
|
|
761
904
|
},
|
|
762
905
|
async delete(releaseId) {
|
|
763
|
-
const release2 = await strapi2.
|
|
764
|
-
where: { id: releaseId },
|
|
906
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
765
907
|
populate: {
|
|
766
908
|
actions: {
|
|
767
|
-
|
|
909
|
+
fields: ["id"]
|
|
768
910
|
}
|
|
769
911
|
}
|
|
770
912
|
});
|
|
@@ -782,13 +924,9 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
782
924
|
}
|
|
783
925
|
}
|
|
784
926
|
});
|
|
785
|
-
await strapi2.
|
|
786
|
-
where: {
|
|
787
|
-
id: releaseId
|
|
788
|
-
}
|
|
789
|
-
});
|
|
927
|
+
await strapi2.entityService.delete(RELEASE_MODEL_UID, releaseId);
|
|
790
928
|
});
|
|
791
|
-
if (
|
|
929
|
+
if (release2.scheduledAt) {
|
|
792
930
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
793
931
|
await schedulingService.cancel(release2.id);
|
|
794
932
|
}
|
|
@@ -796,132 +934,71 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
796
934
|
return release2;
|
|
797
935
|
},
|
|
798
936
|
async publish(releaseId) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
entry: {
|
|
806
|
-
select: ["id"]
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
});
|
|
812
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
937
|
+
const {
|
|
938
|
+
release: release2,
|
|
939
|
+
error
|
|
940
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
941
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
942
|
+
if (!lockedRelease) {
|
|
813
943
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
814
944
|
}
|
|
815
|
-
if (
|
|
945
|
+
if (lockedRelease.releasedAt) {
|
|
816
946
|
throw new errors.ValidationError("Release already published");
|
|
817
947
|
}
|
|
818
|
-
if (
|
|
819
|
-
throw new errors.ValidationError("
|
|
820
|
-
}
|
|
821
|
-
const collectionTypeActions = {};
|
|
822
|
-
const singleTypeActions = [];
|
|
823
|
-
for (const action of releaseWithPopulatedActionEntries.actions) {
|
|
824
|
-
const contentTypeUid = action.contentType;
|
|
825
|
-
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
826
|
-
if (!collectionTypeActions[contentTypeUid]) {
|
|
827
|
-
collectionTypeActions[contentTypeUid] = {
|
|
828
|
-
entriestoPublishIds: [],
|
|
829
|
-
entriesToUnpublishIds: []
|
|
830
|
-
};
|
|
831
|
-
}
|
|
832
|
-
if (action.type === "publish") {
|
|
833
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
834
|
-
} else {
|
|
835
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
836
|
-
}
|
|
837
|
-
} else {
|
|
838
|
-
singleTypeActions.push({
|
|
839
|
-
uid: contentTypeUid,
|
|
840
|
-
action: action.type,
|
|
841
|
-
id: action.entry.id
|
|
842
|
-
});
|
|
843
|
-
}
|
|
948
|
+
if (lockedRelease.status === "failed") {
|
|
949
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
844
950
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
await entityManagerService.publish(entry, uid);
|
|
854
|
-
} else {
|
|
855
|
-
await entityManagerService.unpublish(entry, uid);
|
|
856
|
-
}
|
|
857
|
-
} catch (error) {
|
|
858
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
859
|
-
} else {
|
|
860
|
-
throw error;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
865
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
866
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
867
|
-
const entriesToPublish = await strapi2.db.query(contentTypeUid).findMany({
|
|
868
|
-
where: {
|
|
869
|
-
id: {
|
|
870
|
-
$in: entriestoPublishIds
|
|
871
|
-
}
|
|
872
|
-
},
|
|
873
|
-
populate
|
|
874
|
-
});
|
|
875
|
-
const entriesToUnpublish = await strapi2.db.query(contentTypeUid).findMany({
|
|
876
|
-
where: {
|
|
877
|
-
id: {
|
|
878
|
-
$in: entriesToUnpublishIds
|
|
879
|
-
}
|
|
880
|
-
},
|
|
881
|
-
populate
|
|
882
|
-
});
|
|
883
|
-
if (entriesToPublish.length > 0) {
|
|
884
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
951
|
+
try {
|
|
952
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
953
|
+
const { collectionTypeActions, singleTypeActions } = await getFormattedActions(
|
|
954
|
+
releaseId
|
|
955
|
+
);
|
|
956
|
+
await strapi2.db.transaction(async () => {
|
|
957
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
958
|
+
await publishSingleTypeAction(uid, action, id);
|
|
885
959
|
}
|
|
886
|
-
|
|
887
|
-
|
|
960
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
961
|
+
const uid = contentTypeUid;
|
|
962
|
+
await publishCollectionTypeAction(
|
|
963
|
+
uid,
|
|
964
|
+
collectionTypeActions[uid].entriesToPublishIds,
|
|
965
|
+
collectionTypeActions[uid].entriesToUnpublishIds
|
|
966
|
+
);
|
|
888
967
|
}
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
actions: {
|
|
898
|
-
count: true
|
|
968
|
+
});
|
|
969
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
970
|
+
where: {
|
|
971
|
+
id: releaseId
|
|
972
|
+
},
|
|
973
|
+
data: {
|
|
974
|
+
status: "done",
|
|
975
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
899
976
|
}
|
|
900
|
-
}
|
|
901
|
-
});
|
|
902
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
977
|
+
});
|
|
903
978
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
904
979
|
isPublished: true,
|
|
905
|
-
release:
|
|
980
|
+
release: release22
|
|
906
981
|
});
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
} catch (error) {
|
|
911
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
982
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
983
|
+
return { release: release22, error: null };
|
|
984
|
+
} catch (error2) {
|
|
912
985
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
913
986
|
isPublished: false,
|
|
914
|
-
error
|
|
987
|
+
error: error2
|
|
915
988
|
});
|
|
916
|
-
|
|
917
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
918
|
-
where: { id: releaseId },
|
|
919
|
-
data: {
|
|
989
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
920
990
|
status: "failed"
|
|
921
|
-
}
|
|
922
|
-
|
|
991
|
+
}).transacting(trx).execute();
|
|
992
|
+
return {
|
|
993
|
+
release: null,
|
|
994
|
+
error: error2
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
if (error) {
|
|
923
999
|
throw error;
|
|
924
1000
|
}
|
|
1001
|
+
return release2;
|
|
925
1002
|
},
|
|
926
1003
|
async updateAction(actionId, releaseId, update) {
|
|
927
1004
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -1008,13 +1085,16 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1008
1085
|
}
|
|
1009
1086
|
};
|
|
1010
1087
|
};
|
|
1088
|
+
class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
1089
|
+
constructor(message) {
|
|
1090
|
+
super(message);
|
|
1091
|
+
this.name = "AlreadyOnReleaseError";
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1011
1094
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1012
1095
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1013
|
-
const release2 = await strapi2.
|
|
1014
|
-
|
|
1015
|
-
id: releaseId
|
|
1016
|
-
},
|
|
1017
|
-
populate: { actions: { populate: { entry: { select: ["id"] } } } }
|
|
1096
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
1097
|
+
populate: { actions: { populate: { entry: { fields: ["id"] } } } }
|
|
1018
1098
|
});
|
|
1019
1099
|
if (!release2) {
|
|
1020
1100
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -1023,7 +1103,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1023
1103
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1024
1104
|
);
|
|
1025
1105
|
if (isEntryInRelease) {
|
|
1026
|
-
throw new
|
|
1106
|
+
throw new AlreadyOnReleaseError(
|
|
1027
1107
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1028
1108
|
);
|
|
1029
1109
|
}
|
|
@@ -1033,9 +1113,17 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1033
1113
|
if (!contentType) {
|
|
1034
1114
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1035
1115
|
}
|
|
1116
|
+
if (!contentType.options?.draftAndPublish) {
|
|
1117
|
+
throw new errors.ValidationError(
|
|
1118
|
+
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1036
1121
|
},
|
|
1037
1122
|
async validatePendingReleasesLimit() {
|
|
1038
|
-
const maximumPendingReleases =
|
|
1123
|
+
const maximumPendingReleases = (
|
|
1124
|
+
// @ts-expect-error - options is not typed into features
|
|
1125
|
+
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1126
|
+
);
|
|
1039
1127
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1040
1128
|
filters: {
|
|
1041
1129
|
releasedAt: {
|
|
@@ -1048,8 +1136,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1048
1136
|
}
|
|
1049
1137
|
},
|
|
1050
1138
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1051
|
-
const pendingReleases = await strapi2.
|
|
1052
|
-
|
|
1139
|
+
const pendingReleases = await strapi2.entityService.findMany(RELEASE_MODEL_UID, {
|
|
1140
|
+
filters: {
|
|
1053
1141
|
releasedAt: {
|
|
1054
1142
|
$null: true
|
|
1055
1143
|
},
|
|
@@ -1123,7 +1211,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1123
1211
|
const services = {
|
|
1124
1212
|
release: createReleaseService,
|
|
1125
1213
|
"release-validation": createReleaseValidationService,
|
|
1126
|
-
|
|
1214
|
+
scheduling: createSchedulingService
|
|
1127
1215
|
};
|
|
1128
1216
|
const RELEASE_SCHEMA = yup.object().shape({
|
|
1129
1217
|
name: yup.string().trim().required(),
|
|
@@ -1176,7 +1264,7 @@ const releaseController = {
|
|
|
1176
1264
|
}
|
|
1177
1265
|
};
|
|
1178
1266
|
});
|
|
1179
|
-
const pendingReleasesCount = await strapi.
|
|
1267
|
+
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1180
1268
|
where: {
|
|
1181
1269
|
releasedAt: null
|
|
1182
1270
|
}
|
|
@@ -1299,6 +1387,38 @@ const releaseActionController = {
|
|
|
1299
1387
|
data: releaseAction2
|
|
1300
1388
|
};
|
|
1301
1389
|
},
|
|
1390
|
+
async createMany(ctx) {
|
|
1391
|
+
const releaseId = ctx.params.releaseId;
|
|
1392
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1393
|
+
await Promise.all(
|
|
1394
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1395
|
+
);
|
|
1396
|
+
const releaseService = getService("release", { strapi });
|
|
1397
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1398
|
+
const releaseActions2 = await Promise.all(
|
|
1399
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1400
|
+
try {
|
|
1401
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1402
|
+
return action;
|
|
1403
|
+
} catch (error) {
|
|
1404
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1405
|
+
return null;
|
|
1406
|
+
}
|
|
1407
|
+
throw error;
|
|
1408
|
+
}
|
|
1409
|
+
})
|
|
1410
|
+
);
|
|
1411
|
+
return releaseActions2;
|
|
1412
|
+
});
|
|
1413
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1414
|
+
ctx.body = {
|
|
1415
|
+
data: newReleaseActions,
|
|
1416
|
+
meta: {
|
|
1417
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1418
|
+
totalEntries: releaseActions.length
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
},
|
|
1302
1422
|
async findMany(ctx) {
|
|
1303
1423
|
const releaseId = ctx.params.releaseId;
|
|
1304
1424
|
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
@@ -1322,7 +1442,7 @@ const releaseActionController = {
|
|
|
1322
1442
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1323
1443
|
return acc;
|
|
1324
1444
|
}, {});
|
|
1325
|
-
const sanitizedResults = await
|
|
1445
|
+
const sanitizedResults = await mapAsync(results, async (action) => ({
|
|
1326
1446
|
...action,
|
|
1327
1447
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1328
1448
|
}));
|
|
@@ -1484,6 +1604,22 @@ const releaseAction = {
|
|
|
1484
1604
|
]
|
|
1485
1605
|
}
|
|
1486
1606
|
},
|
|
1607
|
+
{
|
|
1608
|
+
method: "POST",
|
|
1609
|
+
path: "/:releaseId/actions/bulk",
|
|
1610
|
+
handler: "release-action.createMany",
|
|
1611
|
+
config: {
|
|
1612
|
+
policies: [
|
|
1613
|
+
"admin::isAuthenticatedAdmin",
|
|
1614
|
+
{
|
|
1615
|
+
name: "admin::hasPermissions",
|
|
1616
|
+
config: {
|
|
1617
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
]
|
|
1621
|
+
}
|
|
1622
|
+
},
|
|
1487
1623
|
{
|
|
1488
1624
|
method: "GET",
|
|
1489
1625
|
path: "/:releaseId/actions",
|
|
@@ -1538,8 +1674,9 @@ const routes = {
|
|
|
1538
1674
|
release,
|
|
1539
1675
|
"release-action": releaseAction
|
|
1540
1676
|
};
|
|
1677
|
+
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1541
1678
|
const getPlugin = () => {
|
|
1542
|
-
if (
|
|
1679
|
+
if (features.isEnabled("cms-content-releases")) {
|
|
1543
1680
|
return {
|
|
1544
1681
|
register,
|
|
1545
1682
|
bootstrap,
|
|
@@ -1551,6 +1688,9 @@ const getPlugin = () => {
|
|
|
1551
1688
|
};
|
|
1552
1689
|
}
|
|
1553
1690
|
return {
|
|
1691
|
+
// Always return register, it handles its own feature check
|
|
1692
|
+
register,
|
|
1693
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1554
1694
|
contentTypes
|
|
1555
1695
|
};
|
|
1556
1696
|
};
|