@strapi/content-releases 4.20.4 → 5.0.0-alpha.0
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-6ugQxqYE.mjs → App-dbdAcsz_.mjs} +296 -296
- package/dist/_chunks/App-dbdAcsz_.mjs.map +1 -0
- package/dist/_chunks/{App-P1kyM3gT.js → App-zwe_jKPv.js} +301 -301
- package/dist/_chunks/App-zwe_jKPv.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-_eBuegHN.mjs → index-RBaVMtyr.mjs} +79 -70
- package/dist/_chunks/index-RBaVMtyr.mjs.map +1 -0
- package/dist/_chunks/{index-2xzbhaQP.js → index-TBrVNrv9.js} +77 -68
- package/dist/_chunks/index-TBrVNrv9.js.map +1 -0
- package/dist/admin/index.js +1 -14
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +1 -14
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/CMReleasesContainer.d.ts +1 -0
- package/dist/admin/src/components/RelativeTime.d.ts +28 -0
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
- package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
- package/dist/admin/src/components/ReleaseModal.d.ts +16 -0
- package/dist/admin/src/constants.d.ts +58 -0
- package/dist/admin/src/index.d.ts +3 -0
- package/dist/admin/src/pages/App.d.ts +1 -0
- package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
- package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
- package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
- package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
- package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/services/axios.d.ts +29 -0
- package/dist/admin/src/services/release.d.ts +369 -0
- package/dist/admin/src/store/hooks.d.ts +7 -0
- package/dist/admin/src/utils/time.d.ts +1 -0
- package/dist/server/index.js +327 -234
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +328 -234
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -0
- package/dist/server/src/constants.d.ts +12 -0
- package/dist/server/src/constants.d.ts.map +1 -0
- package/dist/server/src/content-types/index.d.ts +99 -0
- package/dist/server/src/content-types/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/index.d.ts +48 -0
- package/dist/server/src/content-types/release/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/schema.d.ts +47 -0
- package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/index.d.ts +50 -0
- package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/schema.d.ts +49 -0
- package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
- package/dist/server/src/controllers/index.d.ts +19 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -0
- package/dist/server/src/controllers/release-action.d.ts +10 -0
- package/dist/server/src/controllers/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/release.d.ts +11 -0
- package/dist/server/src/controllers/release.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release-action.d.ts +3 -0
- package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release.d.ts +2 -0
- package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/destroy.d.ts.map +1 -0
- package/dist/server/src/index.d.ts +2095 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/migrations/index.d.ts +12 -0
- package/dist/server/src/migrations/index.d.ts.map +1 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/register.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts +35 -0
- package/dist/server/src/routes/index.d.ts.map +1 -0
- package/dist/server/src/routes/release-action.d.ts +18 -0
- package/dist/server/src/routes/release-action.d.ts.map +1 -0
- package/dist/server/src/routes/release.d.ts +18 -0
- package/dist/server/src/routes/release.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +1826 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/release.d.ts +66 -0
- package/dist/server/src/services/release.d.ts.map +1 -0
- package/dist/server/src/services/scheduling.d.ts +18 -0
- package/dist/server/src/services/scheduling.d.ts.map +1 -0
- package/dist/server/src/services/validation.d.ts +18 -0
- package/dist/server/src/services/validation.d.ts.map +1 -0
- package/dist/server/src/utils/index.d.ts +14 -0
- package/dist/server/src/utils/index.d.ts.map +1 -0
- package/dist/shared/contracts/release-actions.d.ts +131 -0
- package/dist/shared/contracts/release-actions.d.ts.map +1 -0
- package/dist/shared/contracts/releases.d.ts +166 -0
- package/dist/shared/contracts/releases.d.ts.map +1 -0
- package/dist/shared/types.d.ts +24 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/validation-schemas.d.ts +2 -0
- package/dist/shared/validation-schemas.d.ts.map +1 -0
- package/package.json +24 -30
- package/dist/_chunks/App-6ugQxqYE.mjs.map +0 -1
- package/dist/_chunks/App-P1kyM3gT.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-2xzbhaQP.js.map +0 -1
- package/dist/_chunks/index-_eBuegHN.mjs.map +0 -1
package/dist/server/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { async, setCreatorFields, convertQueryParams, 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";
|
|
6
5
|
import { scheduleJob } from "node-schedule";
|
|
7
6
|
import * as yup from "yup";
|
|
8
7
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
@@ -60,7 +59,10 @@ const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
|
60
59
|
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
61
60
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
62
61
|
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
63
|
-
const entry = await strapi2.
|
|
62
|
+
const entry = await strapi2.db.query(contentTypeUid).findOne({
|
|
63
|
+
where: { id: entryId },
|
|
64
|
+
populate
|
|
65
|
+
});
|
|
64
66
|
return entry;
|
|
65
67
|
};
|
|
66
68
|
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
@@ -77,28 +79,10 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
77
79
|
return false;
|
|
78
80
|
}
|
|
79
81
|
};
|
|
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
|
-
}
|
|
98
82
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
99
83
|
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes2)) ?? [];
|
|
100
84
|
if (deletedContentTypes.length) {
|
|
101
|
-
await
|
|
85
|
+
await async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
102
86
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
103
87
|
});
|
|
104
88
|
}
|
|
@@ -117,7 +101,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
117
101
|
}
|
|
118
102
|
}
|
|
119
103
|
});
|
|
120
|
-
|
|
104
|
+
async.map(releasesWithoutStatus, async (release2) => {
|
|
121
105
|
const actions = release2.actions;
|
|
122
106
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
123
107
|
for (const action of notValidatedActions) {
|
|
@@ -148,7 +132,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
148
132
|
}
|
|
149
133
|
}
|
|
150
134
|
});
|
|
151
|
-
|
|
135
|
+
async.map(publishedReleases, async (release2) => {
|
|
152
136
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
153
137
|
where: {
|
|
154
138
|
id: release2.id
|
|
@@ -161,11 +145,9 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
161
145
|
}
|
|
162
146
|
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
163
147
|
if (oldContentTypes !== void 0 && contentTypes2 !== void 0) {
|
|
164
|
-
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes)
|
|
165
|
-
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
166
|
-
);
|
|
148
|
+
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes);
|
|
167
149
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
168
|
-
|
|
150
|
+
async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
169
151
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
170
152
|
const contentType = contentTypes2[contentTypeUID];
|
|
171
153
|
if (!isEqual(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -178,8 +160,8 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
178
160
|
release: true
|
|
179
161
|
}
|
|
180
162
|
});
|
|
181
|
-
await
|
|
182
|
-
if (action.entry) {
|
|
163
|
+
await async.map(actions, async (action) => {
|
|
164
|
+
if (action.entry && action.release) {
|
|
183
165
|
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
184
166
|
strapi
|
|
185
167
|
});
|
|
@@ -201,26 +183,67 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
201
183
|
});
|
|
202
184
|
}
|
|
203
185
|
}).then(() => {
|
|
204
|
-
|
|
186
|
+
async.map(releasesAffected, async (releaseId) => {
|
|
205
187
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
206
188
|
});
|
|
207
189
|
});
|
|
208
190
|
}
|
|
209
191
|
}
|
|
210
|
-
|
|
192
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
193
|
+
if (!oldContentTypes) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
for (const uid in contentTypes2) {
|
|
197
|
+
if (!oldContentTypes[uid]) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const oldContentType = oldContentTypes[uid];
|
|
201
|
+
const contentType = contentTypes2[uid];
|
|
202
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
203
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
204
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
205
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
206
|
+
locale: null
|
|
207
|
+
}).where({ contentType: uid }).execute();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
212
|
+
if (!oldContentTypes) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
for (const uid in contentTypes2) {
|
|
216
|
+
if (!oldContentTypes[uid]) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const oldContentType = oldContentTypes[uid];
|
|
220
|
+
const contentType = contentTypes2[uid];
|
|
221
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
222
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
223
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
224
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
225
|
+
const defaultLocale = await getDefaultLocale();
|
|
226
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
227
|
+
locale: defaultLocale
|
|
228
|
+
}).where({ contentType: uid }).execute();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
211
232
|
const register = async ({ strapi: strapi2 }) => {
|
|
212
|
-
if (features
|
|
233
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
213
234
|
await strapi2.admin.services.permission.actionProvider.registerMany(ACTIONS);
|
|
214
|
-
strapi2.hook("strapi::content-types.beforeSync").register(
|
|
215
|
-
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
235
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized);
|
|
236
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
237
|
+
}
|
|
238
|
+
if (strapi2.plugin("graphql")) {
|
|
239
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
240
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
241
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
216
242
|
}
|
|
217
243
|
};
|
|
218
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
219
244
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
220
|
-
if (features
|
|
221
|
-
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes)
|
|
222
|
-
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
223
|
-
);
|
|
245
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
246
|
+
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes);
|
|
224
247
|
strapi2.db.lifecycles.subscribe({
|
|
225
248
|
models: contentTypesWithDraftAndPublish,
|
|
226
249
|
async afterDelete(event) {
|
|
@@ -256,7 +279,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
256
279
|
*/
|
|
257
280
|
async beforeDeleteMany(event) {
|
|
258
281
|
const { model, params } = event;
|
|
259
|
-
if (model.kind === "collectionType"
|
|
282
|
+
if (model.kind === "collectionType") {
|
|
260
283
|
const { where } = params;
|
|
261
284
|
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
262
285
|
event.state.entriesToDelete = entriesToDelete;
|
|
@@ -338,27 +361,23 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
338
361
|
}
|
|
339
362
|
}
|
|
340
363
|
});
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
});
|
|
351
|
-
}
|
|
364
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
365
|
+
strapi2.log.error(
|
|
366
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
367
|
+
);
|
|
368
|
+
throw err;
|
|
369
|
+
});
|
|
370
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
371
|
+
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
372
|
+
});
|
|
352
373
|
}
|
|
353
374
|
};
|
|
354
375
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
job.cancel();
|
|
361
|
-
}
|
|
376
|
+
const scheduledJobs = getService("scheduling", {
|
|
377
|
+
strapi: strapi2
|
|
378
|
+
}).getAll();
|
|
379
|
+
for (const [, job] of scheduledJobs) {
|
|
380
|
+
job.cancel();
|
|
362
381
|
}
|
|
363
382
|
};
|
|
364
383
|
const schema$1 = {
|
|
@@ -483,6 +502,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
483
502
|
release: release2
|
|
484
503
|
});
|
|
485
504
|
};
|
|
505
|
+
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
506
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
507
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
508
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
509
|
+
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
510
|
+
try {
|
|
511
|
+
if (actionType === "publish") {
|
|
512
|
+
await entityManagerService.publish(entry, uid);
|
|
513
|
+
} else {
|
|
514
|
+
await entityManagerService.unpublish(entry, uid);
|
|
515
|
+
}
|
|
516
|
+
} catch (error) {
|
|
517
|
+
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
518
|
+
;
|
|
519
|
+
else {
|
|
520
|
+
throw error;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
525
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
526
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
527
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
528
|
+
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
529
|
+
filters: {
|
|
530
|
+
id: {
|
|
531
|
+
$in: entriesToPublishIds
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
populate
|
|
535
|
+
});
|
|
536
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
537
|
+
filters: {
|
|
538
|
+
id: {
|
|
539
|
+
$in: entriestoUnpublishIds
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
populate
|
|
543
|
+
});
|
|
544
|
+
if (entriesToPublish.length > 0) {
|
|
545
|
+
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
546
|
+
}
|
|
547
|
+
if (entriesToUnpublish.length > 0) {
|
|
548
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
const getFormattedActions = async (releaseId) => {
|
|
552
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
553
|
+
where: {
|
|
554
|
+
release: {
|
|
555
|
+
id: releaseId
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
populate: {
|
|
559
|
+
entry: {
|
|
560
|
+
fields: ["id"]
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
if (actions.length === 0) {
|
|
565
|
+
throw new errors.ValidationError("No entries to publish");
|
|
566
|
+
}
|
|
567
|
+
const collectionTypeActions = {};
|
|
568
|
+
const singleTypeActions = [];
|
|
569
|
+
for (const action of actions) {
|
|
570
|
+
const contentTypeUid = action.contentType;
|
|
571
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
572
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
573
|
+
collectionTypeActions[contentTypeUid] = {
|
|
574
|
+
entriesToPublishIds: [],
|
|
575
|
+
entriesToUnpublishIds: []
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
if (action.type === "publish") {
|
|
579
|
+
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
580
|
+
} else {
|
|
581
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
singleTypeActions.push({
|
|
585
|
+
uid: contentTypeUid,
|
|
586
|
+
action: action.type,
|
|
587
|
+
id: action.entry.id
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return { collectionTypeActions, singleTypeActions };
|
|
592
|
+
};
|
|
486
593
|
return {
|
|
487
594
|
async create(releaseData, { user }) {
|
|
488
595
|
const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
|
|
@@ -496,13 +603,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
496
603
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
497
604
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
498
605
|
]);
|
|
499
|
-
const release2 = await strapi2.
|
|
606
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
500
607
|
data: {
|
|
501
608
|
...releaseWithCreatorFields,
|
|
502
609
|
status: "empty"
|
|
503
610
|
}
|
|
504
611
|
});
|
|
505
|
-
if (
|
|
612
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
506
613
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
507
614
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
508
615
|
}
|
|
@@ -510,17 +617,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
510
617
|
return release2;
|
|
511
618
|
},
|
|
512
619
|
async findOne(id, query = {}) {
|
|
513
|
-
const
|
|
514
|
-
|
|
620
|
+
const dbQuery = convertQueryParams.transformParamsToQuery(RELEASE_MODEL_UID, query);
|
|
621
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
622
|
+
...dbQuery,
|
|
623
|
+
where: { id }
|
|
515
624
|
});
|
|
516
625
|
return release2;
|
|
517
626
|
},
|
|
518
627
|
findPage(query) {
|
|
519
|
-
|
|
520
|
-
|
|
628
|
+
const dbQuery = convertQueryParams.transformParamsToQuery(RELEASE_MODEL_UID, query ?? {});
|
|
629
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
630
|
+
...dbQuery,
|
|
521
631
|
populate: {
|
|
522
632
|
actions: {
|
|
523
|
-
// @ts-expect-error Ignore missing properties
|
|
524
633
|
count: true
|
|
525
634
|
}
|
|
526
635
|
}
|
|
@@ -612,28 +721,22 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
612
721
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
613
722
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
614
723
|
]);
|
|
615
|
-
const release2 = await strapi2.
|
|
724
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
616
725
|
if (!release2) {
|
|
617
726
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
618
727
|
}
|
|
619
728
|
if (release2.releasedAt) {
|
|
620
729
|
throw new errors.ValidationError("Release already published");
|
|
621
730
|
}
|
|
622
|
-
const updatedRelease = await strapi2.
|
|
623
|
-
|
|
624
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
625
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
626
|
-
*/
|
|
627
|
-
// @ts-expect-error see above
|
|
731
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
732
|
+
where: { id },
|
|
628
733
|
data: releaseWithCreatorFields
|
|
629
734
|
});
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
schedulingService.cancel(id);
|
|
636
|
-
}
|
|
735
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
736
|
+
if (releaseData.scheduledAt) {
|
|
737
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
738
|
+
} else if (release2.scheduledAt) {
|
|
739
|
+
schedulingService.cancel(id);
|
|
637
740
|
}
|
|
638
741
|
this.updateReleaseStatus(id);
|
|
639
742
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
@@ -647,7 +750,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
647
750
|
validateEntryContentType(action.entry.contentType),
|
|
648
751
|
validateUniqueEntry(releaseId, action)
|
|
649
752
|
]);
|
|
650
|
-
const release2 = await strapi2.
|
|
753
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
651
754
|
if (!release2) {
|
|
652
755
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
653
756
|
}
|
|
@@ -657,7 +760,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
657
760
|
const { entry, type } = action;
|
|
658
761
|
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
659
762
|
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
660
|
-
const releaseAction2 = await strapi2.
|
|
763
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
661
764
|
data: {
|
|
662
765
|
type,
|
|
663
766
|
contentType: entry.contentType,
|
|
@@ -670,32 +773,41 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
670
773
|
},
|
|
671
774
|
release: releaseId
|
|
672
775
|
},
|
|
673
|
-
populate: { release: {
|
|
776
|
+
populate: { release: { select: ["id"] }, entry: { select: ["id"] } }
|
|
674
777
|
});
|
|
675
778
|
this.updateReleaseStatus(releaseId);
|
|
676
779
|
return releaseAction2;
|
|
677
780
|
},
|
|
678
781
|
async findActions(releaseId, query) {
|
|
679
|
-
const release2 = await strapi2.
|
|
680
|
-
|
|
782
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
783
|
+
where: { id: releaseId },
|
|
784
|
+
select: ["id"]
|
|
681
785
|
});
|
|
682
786
|
if (!release2) {
|
|
683
787
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
684
788
|
}
|
|
685
|
-
|
|
686
|
-
|
|
789
|
+
const dbQuery = convertQueryParams.transformParamsToQuery(
|
|
790
|
+
RELEASE_ACTION_MODEL_UID,
|
|
791
|
+
query ?? {}
|
|
792
|
+
);
|
|
793
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
794
|
+
...dbQuery,
|
|
687
795
|
populate: {
|
|
688
796
|
entry: {
|
|
689
797
|
populate: "*"
|
|
690
798
|
}
|
|
691
799
|
},
|
|
692
|
-
|
|
800
|
+
where: {
|
|
693
801
|
release: releaseId
|
|
694
802
|
}
|
|
695
803
|
});
|
|
696
804
|
},
|
|
697
805
|
async countActions(query) {
|
|
698
|
-
|
|
806
|
+
const dbQuery = convertQueryParams.transformParamsToQuery(
|
|
807
|
+
RELEASE_ACTION_MODEL_UID,
|
|
808
|
+
query ?? {}
|
|
809
|
+
);
|
|
810
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
699
811
|
},
|
|
700
812
|
async groupActions(actions, groupBy) {
|
|
701
813
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -776,10 +888,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
776
888
|
return componentsMap;
|
|
777
889
|
},
|
|
778
890
|
async delete(releaseId) {
|
|
779
|
-
const release2 = await strapi2.
|
|
891
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
892
|
+
where: { id: releaseId },
|
|
780
893
|
populate: {
|
|
781
894
|
actions: {
|
|
782
|
-
|
|
895
|
+
select: ["id"]
|
|
783
896
|
}
|
|
784
897
|
}
|
|
785
898
|
});
|
|
@@ -797,9 +910,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
797
910
|
}
|
|
798
911
|
}
|
|
799
912
|
});
|
|
800
|
-
await strapi2.
|
|
913
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
914
|
+
where: {
|
|
915
|
+
id: releaseId
|
|
916
|
+
}
|
|
917
|
+
});
|
|
801
918
|
});
|
|
802
|
-
if (
|
|
919
|
+
if (release2.scheduledAt) {
|
|
803
920
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
804
921
|
await schedulingService.cancel(release2.id);
|
|
805
922
|
}
|
|
@@ -807,145 +924,71 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
807
924
|
return release2;
|
|
808
925
|
},
|
|
809
926
|
async publish(releaseId) {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
actions: {
|
|
817
|
-
populate: {
|
|
818
|
-
entry: {
|
|
819
|
-
fields: ["id"]
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
);
|
|
826
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
927
|
+
const {
|
|
928
|
+
release: release2,
|
|
929
|
+
error
|
|
930
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
931
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
932
|
+
if (!lockedRelease) {
|
|
827
933
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
828
934
|
}
|
|
829
|
-
if (
|
|
935
|
+
if (lockedRelease.releasedAt) {
|
|
830
936
|
throw new errors.ValidationError("Release already published");
|
|
831
937
|
}
|
|
832
|
-
if (
|
|
833
|
-
throw new errors.ValidationError("
|
|
938
|
+
if (lockedRelease.status === "failed") {
|
|
939
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
834
940
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
entriesToUnpublishIds: []
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
|
-
if (action.type === "publish") {
|
|
847
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
848
|
-
} else {
|
|
849
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
850
|
-
}
|
|
851
|
-
} else {
|
|
852
|
-
singleTypeActions.push({
|
|
853
|
-
uid: contentTypeUid,
|
|
854
|
-
action: action.type,
|
|
855
|
-
id: action.entry.id
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
860
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
861
|
-
await strapi2.db.transaction(async () => {
|
|
862
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
863
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
864
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
865
|
-
try {
|
|
866
|
-
if (action === "publish") {
|
|
867
|
-
await entityManagerService.publish(entry, uid);
|
|
868
|
-
} else {
|
|
869
|
-
await entityManagerService.unpublish(entry, uid);
|
|
870
|
-
}
|
|
871
|
-
} catch (error) {
|
|
872
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
873
|
-
} else {
|
|
874
|
-
throw error;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
879
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
880
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
881
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
882
|
-
contentTypeUid,
|
|
883
|
-
{
|
|
884
|
-
filters: {
|
|
885
|
-
id: {
|
|
886
|
-
$in: entriestoPublishIds
|
|
887
|
-
}
|
|
888
|
-
},
|
|
889
|
-
populate
|
|
890
|
-
}
|
|
891
|
-
);
|
|
892
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
893
|
-
contentTypeUid,
|
|
894
|
-
{
|
|
895
|
-
filters: {
|
|
896
|
-
id: {
|
|
897
|
-
$in: entriesToUnpublishIds
|
|
898
|
-
}
|
|
899
|
-
},
|
|
900
|
-
populate
|
|
901
|
-
}
|
|
902
|
-
);
|
|
903
|
-
if (entriesToPublish.length > 0) {
|
|
904
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
941
|
+
try {
|
|
942
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
943
|
+
const { collectionTypeActions, singleTypeActions } = await getFormattedActions(
|
|
944
|
+
releaseId
|
|
945
|
+
);
|
|
946
|
+
await strapi2.db.transaction(async () => {
|
|
947
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
948
|
+
await publishSingleTypeAction(uid, action, id);
|
|
905
949
|
}
|
|
906
|
-
|
|
907
|
-
|
|
950
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
951
|
+
const uid = contentTypeUid;
|
|
952
|
+
await publishCollectionTypeAction(
|
|
953
|
+
uid,
|
|
954
|
+
collectionTypeActions[uid].entriesToPublishIds,
|
|
955
|
+
collectionTypeActions[uid].entriesToUnpublishIds
|
|
956
|
+
);
|
|
908
957
|
}
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
918
|
-
},
|
|
919
|
-
populate: {
|
|
920
|
-
actions: {
|
|
921
|
-
// @ts-expect-error is not expecting count but it is working
|
|
922
|
-
count: true
|
|
958
|
+
});
|
|
959
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
960
|
+
where: {
|
|
961
|
+
id: releaseId
|
|
962
|
+
},
|
|
963
|
+
data: {
|
|
964
|
+
status: "done",
|
|
965
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
923
966
|
}
|
|
924
|
-
}
|
|
925
|
-
});
|
|
926
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
967
|
+
});
|
|
927
968
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
928
969
|
isPublished: true,
|
|
929
|
-
release:
|
|
970
|
+
release: release22
|
|
930
971
|
});
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
} catch (error) {
|
|
935
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
972
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
973
|
+
return { release: release22, error: null };
|
|
974
|
+
} catch (error2) {
|
|
936
975
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
937
976
|
isPublished: false,
|
|
938
|
-
error
|
|
977
|
+
error: error2
|
|
939
978
|
});
|
|
940
|
-
|
|
941
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
942
|
-
where: { id: releaseId },
|
|
943
|
-
data: {
|
|
979
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
944
980
|
status: "failed"
|
|
945
|
-
}
|
|
946
|
-
|
|
981
|
+
}).transacting(trx).execute();
|
|
982
|
+
return {
|
|
983
|
+
release: null,
|
|
984
|
+
error: error2
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
if (error instanceof Error) {
|
|
947
989
|
throw error;
|
|
948
990
|
}
|
|
991
|
+
return release2;
|
|
949
992
|
},
|
|
950
993
|
async updateAction(actionId, releaseId, update) {
|
|
951
994
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -1032,10 +1075,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1032
1075
|
}
|
|
1033
1076
|
};
|
|
1034
1077
|
};
|
|
1078
|
+
class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
1079
|
+
constructor(message) {
|
|
1080
|
+
super(message);
|
|
1081
|
+
this.name = "AlreadyOnReleaseError";
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1035
1084
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1036
1085
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1037
|
-
const release2 = await strapi2.
|
|
1038
|
-
|
|
1086
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1087
|
+
where: {
|
|
1088
|
+
id: releaseId
|
|
1089
|
+
},
|
|
1090
|
+
populate: { actions: { populate: { entry: { select: ["id"] } } } }
|
|
1039
1091
|
});
|
|
1040
1092
|
if (!release2) {
|
|
1041
1093
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -1044,7 +1096,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1044
1096
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1045
1097
|
);
|
|
1046
1098
|
if (isEntryInRelease) {
|
|
1047
|
-
throw new
|
|
1099
|
+
throw new AlreadyOnReleaseError(
|
|
1048
1100
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1049
1101
|
);
|
|
1050
1102
|
}
|
|
@@ -1054,17 +1106,9 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1054
1106
|
if (!contentType) {
|
|
1055
1107
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1056
1108
|
}
|
|
1057
|
-
if (!contentType.options?.draftAndPublish) {
|
|
1058
|
-
throw new errors.ValidationError(
|
|
1059
|
-
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1060
|
-
);
|
|
1061
|
-
}
|
|
1062
1109
|
},
|
|
1063
1110
|
async validatePendingReleasesLimit() {
|
|
1064
|
-
const maximumPendingReleases = (
|
|
1065
|
-
// @ts-expect-error - options is not typed into features
|
|
1066
|
-
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1067
|
-
);
|
|
1111
|
+
const maximumPendingReleases = strapi2.ee.features.get("cms-content-releases")?.options?.maximumReleases || 3;
|
|
1068
1112
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1069
1113
|
filters: {
|
|
1070
1114
|
releasedAt: {
|
|
@@ -1077,8 +1121,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1077
1121
|
}
|
|
1078
1122
|
},
|
|
1079
1123
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1080
|
-
const pendingReleases = await strapi2.
|
|
1081
|
-
|
|
1124
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1125
|
+
where: {
|
|
1082
1126
|
releasedAt: {
|
|
1083
1127
|
$null: true
|
|
1084
1128
|
},
|
|
@@ -1152,7 +1196,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1152
1196
|
const services = {
|
|
1153
1197
|
release: createReleaseService,
|
|
1154
1198
|
"release-validation": createReleaseValidationService,
|
|
1155
|
-
|
|
1199
|
+
scheduling: createSchedulingService
|
|
1156
1200
|
};
|
|
1157
1201
|
const RELEASE_SCHEMA = yup.object().shape({
|
|
1158
1202
|
name: yup.string().trim().required(),
|
|
@@ -1205,7 +1249,7 @@ const releaseController = {
|
|
|
1205
1249
|
}
|
|
1206
1250
|
};
|
|
1207
1251
|
});
|
|
1208
|
-
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1252
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1209
1253
|
where: {
|
|
1210
1254
|
releasedAt: null
|
|
1211
1255
|
}
|
|
@@ -1328,6 +1372,38 @@ const releaseActionController = {
|
|
|
1328
1372
|
data: releaseAction2
|
|
1329
1373
|
};
|
|
1330
1374
|
},
|
|
1375
|
+
async createMany(ctx) {
|
|
1376
|
+
const releaseId = ctx.params.releaseId;
|
|
1377
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1378
|
+
await Promise.all(
|
|
1379
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1380
|
+
);
|
|
1381
|
+
const releaseService = getService("release", { strapi });
|
|
1382
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1383
|
+
const releaseActions2 = await Promise.all(
|
|
1384
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1385
|
+
try {
|
|
1386
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1387
|
+
return action;
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1390
|
+
return null;
|
|
1391
|
+
}
|
|
1392
|
+
throw error;
|
|
1393
|
+
}
|
|
1394
|
+
})
|
|
1395
|
+
);
|
|
1396
|
+
return releaseActions2;
|
|
1397
|
+
});
|
|
1398
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1399
|
+
ctx.body = {
|
|
1400
|
+
data: newReleaseActions,
|
|
1401
|
+
meta: {
|
|
1402
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1403
|
+
totalEntries: releaseActions.length
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
},
|
|
1331
1407
|
async findMany(ctx) {
|
|
1332
1408
|
const releaseId = ctx.params.releaseId;
|
|
1333
1409
|
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
@@ -1351,7 +1427,7 @@ const releaseActionController = {
|
|
|
1351
1427
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1352
1428
|
return acc;
|
|
1353
1429
|
}, {});
|
|
1354
|
-
const sanitizedResults = await
|
|
1430
|
+
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1355
1431
|
...action,
|
|
1356
1432
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1357
1433
|
}));
|
|
@@ -1513,6 +1589,22 @@ const releaseAction = {
|
|
|
1513
1589
|
]
|
|
1514
1590
|
}
|
|
1515
1591
|
},
|
|
1592
|
+
{
|
|
1593
|
+
method: "POST",
|
|
1594
|
+
path: "/:releaseId/actions/bulk",
|
|
1595
|
+
handler: "release-action.createMany",
|
|
1596
|
+
config: {
|
|
1597
|
+
policies: [
|
|
1598
|
+
"admin::isAuthenticatedAdmin",
|
|
1599
|
+
{
|
|
1600
|
+
name: "admin::hasPermissions",
|
|
1601
|
+
config: {
|
|
1602
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
]
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1516
1608
|
{
|
|
1517
1609
|
method: "GET",
|
|
1518
1610
|
path: "/:releaseId/actions",
|
|
@@ -1567,9 +1659,8 @@ const routes = {
|
|
|
1567
1659
|
release,
|
|
1568
1660
|
"release-action": releaseAction
|
|
1569
1661
|
};
|
|
1570
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1571
1662
|
const getPlugin = () => {
|
|
1572
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1663
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1573
1664
|
return {
|
|
1574
1665
|
register,
|
|
1575
1666
|
bootstrap,
|
|
@@ -1581,6 +1672,9 @@ const getPlugin = () => {
|
|
|
1581
1672
|
};
|
|
1582
1673
|
}
|
|
1583
1674
|
return {
|
|
1675
|
+
// Always return register, it handles its own feature check
|
|
1676
|
+
register,
|
|
1677
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1584
1678
|
contentTypes
|
|
1585
1679
|
};
|
|
1586
1680
|
};
|