@strapi/content-releases 0.0.0-experimental.e3e48deb89bd0a1b6cc69b698696566fa7854a95 → 0.0.0-experimental.e47108ccbbc4ad1bfaf4526fa6b70d6ace1ca7a9
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-XbK-TdJn.mjs} +258 -283
- package/dist/_chunks/App-XbK-TdJn.mjs.map +1 -0
- package/dist/_chunks/{App-lzeJz92X.js → App-ftICpqDz.js} +256 -281
- package/dist/_chunks/App-ftICpqDz.js.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-4CUzVH2g.js} +2 -3
- package/dist/_chunks/en-4CUzVH2g.js.map +1 -0
- package/dist/_chunks/{en-WuuhP6Bn.mjs → en-pOJ6G5fC.mjs} +2 -3
- package/dist/_chunks/en-pOJ6G5fC.mjs.map +1 -0
- package/dist/_chunks/{index--4AgLDzb.mjs → index-8LrruHqK.mjs} +33 -27
- package/dist/_chunks/index-8LrruHqK.mjs.map +1 -0
- package/dist/_chunks/{index-Nf1JfI-m.js → index-RYVGXFeL.js} +29 -23
- package/dist/_chunks/index-RYVGXFeL.js.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/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--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.js
CHANGED
|
@@ -3,6 +3,7 @@ const utils = require("@strapi/utils");
|
|
|
3
3
|
const isEqual = require("lodash/isEqual");
|
|
4
4
|
const lodash = require("lodash");
|
|
5
5
|
const _ = require("lodash/fp");
|
|
6
|
+
const EE = require("@strapi/strapi/dist/utils/ee");
|
|
6
7
|
const nodeSchedule = require("node-schedule");
|
|
7
8
|
const yup = require("yup");
|
|
8
9
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -26,6 +27,7 @@ function _interopNamespace(e) {
|
|
|
26
27
|
}
|
|
27
28
|
const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
|
|
28
29
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
30
|
+
const EE__default = /* @__PURE__ */ _interopDefault(EE);
|
|
29
31
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
30
32
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
31
33
|
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
@@ -82,10 +84,7 @@ const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
|
82
84
|
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
83
85
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
84
86
|
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
85
|
-
const entry = await strapi2.
|
|
86
|
-
where: { id: entryId },
|
|
87
|
-
populate
|
|
88
|
-
});
|
|
87
|
+
const entry = await strapi2.entityService.findOne(contentTypeUid, entryId, { populate });
|
|
89
88
|
return entry;
|
|
90
89
|
};
|
|
91
90
|
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
@@ -102,10 +101,28 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
102
101
|
return false;
|
|
103
102
|
}
|
|
104
103
|
};
|
|
104
|
+
async function deleteActionsOnDisableDraftAndPublish({
|
|
105
|
+
oldContentTypes,
|
|
106
|
+
contentTypes: contentTypes2
|
|
107
|
+
}) {
|
|
108
|
+
if (!oldContentTypes) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
for (const uid in contentTypes2) {
|
|
112
|
+
if (!oldContentTypes[uid]) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const oldContentType = oldContentTypes[uid];
|
|
116
|
+
const contentType = contentTypes2[uid];
|
|
117
|
+
if (utils.contentTypes.hasDraftAndPublish(oldContentType) && !utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
118
|
+
await strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: uid }).execute();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
105
122
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
106
123
|
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
107
124
|
if (deletedContentTypes.length) {
|
|
108
|
-
await utils.
|
|
125
|
+
await utils.mapAsync(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
109
126
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
110
127
|
});
|
|
111
128
|
}
|
|
@@ -124,7 +141,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
124
141
|
}
|
|
125
142
|
}
|
|
126
143
|
});
|
|
127
|
-
utils.
|
|
144
|
+
utils.mapAsync(releasesWithoutStatus, async (release2) => {
|
|
128
145
|
const actions = release2.actions;
|
|
129
146
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
130
147
|
for (const action of notValidatedActions) {
|
|
@@ -155,7 +172,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
155
172
|
}
|
|
156
173
|
}
|
|
157
174
|
});
|
|
158
|
-
utils.
|
|
175
|
+
utils.mapAsync(publishedReleases, async (release2) => {
|
|
159
176
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
160
177
|
where: {
|
|
161
178
|
id: release2.id
|
|
@@ -168,9 +185,11 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
168
185
|
}
|
|
169
186
|
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
170
187
|
if (oldContentTypes !== void 0 && contentTypes2 !== void 0) {
|
|
171
|
-
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes)
|
|
188
|
+
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes).filter(
|
|
189
|
+
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
190
|
+
);
|
|
172
191
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
173
|
-
utils.
|
|
192
|
+
utils.mapAsync(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
174
193
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
175
194
|
const contentType = contentTypes2[contentTypeUID];
|
|
176
195
|
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -183,8 +202,8 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
183
202
|
release: true
|
|
184
203
|
}
|
|
185
204
|
});
|
|
186
|
-
await utils.
|
|
187
|
-
if (action.entry) {
|
|
205
|
+
await utils.mapAsync(actions, async (action) => {
|
|
206
|
+
if (action.entry && action.release) {
|
|
188
207
|
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
189
208
|
strapi
|
|
190
209
|
});
|
|
@@ -206,21 +225,71 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
206
225
|
});
|
|
207
226
|
}
|
|
208
227
|
}).then(() => {
|
|
209
|
-
utils.
|
|
228
|
+
utils.mapAsync(releasesAffected, async (releaseId) => {
|
|
210
229
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
211
230
|
});
|
|
212
231
|
});
|
|
213
232
|
}
|
|
214
233
|
}
|
|
234
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
235
|
+
if (!oldContentTypes) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
for (const uid in contentTypes2) {
|
|
239
|
+
if (!oldContentTypes[uid]) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const oldContentType = oldContentTypes[uid];
|
|
243
|
+
const contentType = contentTypes2[uid];
|
|
244
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
245
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
246
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
247
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
248
|
+
locale: null
|
|
249
|
+
}).where({ contentType: uid }).execute();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
254
|
+
if (!oldContentTypes) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
for (const uid in contentTypes2) {
|
|
258
|
+
if (!oldContentTypes[uid]) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const oldContentType = oldContentTypes[uid];
|
|
262
|
+
const contentType = contentTypes2[uid];
|
|
263
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
264
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
265
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
266
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
267
|
+
const defaultLocale = await getDefaultLocale();
|
|
268
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
269
|
+
locale: defaultLocale
|
|
270
|
+
}).where({ contentType: uid }).execute();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
|
|
215
275
|
const register = async ({ strapi: strapi2 }) => {
|
|
216
|
-
if (
|
|
276
|
+
if (features$2.isEnabled("cms-content-releases")) {
|
|
217
277
|
await strapi2.admin.services.permission.actionProvider.registerMany(ACTIONS);
|
|
218
|
-
strapi2.hook("strapi::content-types.
|
|
278
|
+
strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish).register(disableContentTypeLocalized);
|
|
279
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
280
|
+
}
|
|
281
|
+
if (strapi2.plugin("graphql")) {
|
|
282
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
283
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
284
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
219
285
|
}
|
|
220
286
|
};
|
|
287
|
+
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
221
288
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
222
|
-
if (
|
|
223
|
-
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes)
|
|
289
|
+
if (features$1.isEnabled("cms-content-releases")) {
|
|
290
|
+
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
291
|
+
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
292
|
+
);
|
|
224
293
|
strapi2.db.lifecycles.subscribe({
|
|
225
294
|
models: contentTypesWithDraftAndPublish,
|
|
226
295
|
async afterDelete(event) {
|
|
@@ -256,7 +325,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
256
325
|
*/
|
|
257
326
|
async beforeDeleteMany(event) {
|
|
258
327
|
const { model, params } = event;
|
|
259
|
-
if (model.kind === "collectionType") {
|
|
328
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
260
329
|
const { where } = params;
|
|
261
330
|
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
262
331
|
event.state.entriesToDelete = entriesToDelete;
|
|
@@ -338,27 +407,23 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
338
407
|
}
|
|
339
408
|
}
|
|
340
409
|
});
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
});
|
|
351
|
-
}
|
|
410
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
411
|
+
strapi2.log.error(
|
|
412
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
413
|
+
);
|
|
414
|
+
throw err;
|
|
415
|
+
});
|
|
416
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
417
|
+
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
418
|
+
});
|
|
352
419
|
}
|
|
353
420
|
};
|
|
354
421
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
job.cancel();
|
|
361
|
-
}
|
|
422
|
+
const scheduledJobs = getService("scheduling", {
|
|
423
|
+
strapi: strapi2
|
|
424
|
+
}).getAll();
|
|
425
|
+
for (const [, job] of scheduledJobs) {
|
|
426
|
+
job.cancel();
|
|
362
427
|
}
|
|
363
428
|
};
|
|
364
429
|
const schema$1 = {
|
|
@@ -483,6 +548,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
483
548
|
release: release2
|
|
484
549
|
});
|
|
485
550
|
};
|
|
551
|
+
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
552
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
553
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
554
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
555
|
+
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
556
|
+
try {
|
|
557
|
+
if (actionType === "publish") {
|
|
558
|
+
await entityManagerService.publish(entry, uid);
|
|
559
|
+
} else {
|
|
560
|
+
await entityManagerService.unpublish(entry, uid);
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
564
|
+
;
|
|
565
|
+
else {
|
|
566
|
+
throw error;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
571
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
572
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
573
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
574
|
+
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
575
|
+
filters: {
|
|
576
|
+
id: {
|
|
577
|
+
$in: entriesToPublishIds
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
populate
|
|
581
|
+
});
|
|
582
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
583
|
+
filters: {
|
|
584
|
+
id: {
|
|
585
|
+
$in: entriestoUnpublishIds
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
populate
|
|
589
|
+
});
|
|
590
|
+
if (entriesToPublish.length > 0) {
|
|
591
|
+
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
592
|
+
}
|
|
593
|
+
if (entriesToUnpublish.length > 0) {
|
|
594
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
const getFormattedActions = async (releaseId) => {
|
|
598
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
599
|
+
where: {
|
|
600
|
+
release: {
|
|
601
|
+
id: releaseId
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
populate: {
|
|
605
|
+
entry: {
|
|
606
|
+
fields: ["id"]
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
if (actions.length === 0) {
|
|
611
|
+
throw new utils.errors.ValidationError("No entries to publish");
|
|
612
|
+
}
|
|
613
|
+
const collectionTypeActions = {};
|
|
614
|
+
const singleTypeActions = [];
|
|
615
|
+
for (const action of actions) {
|
|
616
|
+
const contentTypeUid = action.contentType;
|
|
617
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
618
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
619
|
+
collectionTypeActions[contentTypeUid] = {
|
|
620
|
+
entriesToPublishIds: [],
|
|
621
|
+
entriesToUnpublishIds: []
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
if (action.type === "publish") {
|
|
625
|
+
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
626
|
+
} else {
|
|
627
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
628
|
+
}
|
|
629
|
+
} else {
|
|
630
|
+
singleTypeActions.push({
|
|
631
|
+
uid: contentTypeUid,
|
|
632
|
+
action: action.type,
|
|
633
|
+
id: action.entry.id
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return { collectionTypeActions, singleTypeActions };
|
|
638
|
+
};
|
|
486
639
|
return {
|
|
487
640
|
async create(releaseData, { user }) {
|
|
488
641
|
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
@@ -496,13 +649,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
496
649
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
497
650
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
498
651
|
]);
|
|
499
|
-
const release2 = await strapi2.
|
|
652
|
+
const release2 = await strapi2.entityService.create(RELEASE_MODEL_UID, {
|
|
500
653
|
data: {
|
|
501
654
|
...releaseWithCreatorFields,
|
|
502
655
|
status: "empty"
|
|
503
656
|
}
|
|
504
657
|
});
|
|
505
|
-
if (
|
|
658
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
506
659
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
507
660
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
508
661
|
}
|
|
@@ -510,19 +663,17 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
510
663
|
return release2;
|
|
511
664
|
},
|
|
512
665
|
async findOne(id, query = {}) {
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
...dbQuery,
|
|
516
|
-
where: { id }
|
|
666
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, id, {
|
|
667
|
+
...query
|
|
517
668
|
});
|
|
518
669
|
return release2;
|
|
519
670
|
},
|
|
520
671
|
findPage(query) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
...dbQuery,
|
|
672
|
+
return strapi2.entityService.findPage(RELEASE_MODEL_UID, {
|
|
673
|
+
...query,
|
|
524
674
|
populate: {
|
|
525
675
|
actions: {
|
|
676
|
+
// @ts-expect-error Ignore missing properties
|
|
526
677
|
count: true
|
|
527
678
|
}
|
|
528
679
|
}
|
|
@@ -614,24 +765,26 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
614
765
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
615
766
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
616
767
|
]);
|
|
617
|
-
const release2 = await strapi2.
|
|
768
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, id);
|
|
618
769
|
if (!release2) {
|
|
619
770
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
620
771
|
}
|
|
621
772
|
if (release2.releasedAt) {
|
|
622
773
|
throw new utils.errors.ValidationError("Release already published");
|
|
623
774
|
}
|
|
624
|
-
const updatedRelease = await strapi2.
|
|
625
|
-
|
|
775
|
+
const updatedRelease = await strapi2.entityService.update(RELEASE_MODEL_UID, id, {
|
|
776
|
+
/*
|
|
777
|
+
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
778
|
+
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
779
|
+
*/
|
|
780
|
+
// @ts-expect-error see above
|
|
626
781
|
data: releaseWithCreatorFields
|
|
627
782
|
});
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
schedulingService.cancel(id);
|
|
634
|
-
}
|
|
783
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
784
|
+
if (releaseData.scheduledAt) {
|
|
785
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
786
|
+
} else if (release2.scheduledAt) {
|
|
787
|
+
schedulingService.cancel(id);
|
|
635
788
|
}
|
|
636
789
|
this.updateReleaseStatus(id);
|
|
637
790
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
@@ -645,7 +798,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
645
798
|
validateEntryContentType(action.entry.contentType),
|
|
646
799
|
validateUniqueEntry(releaseId, action)
|
|
647
800
|
]);
|
|
648
|
-
const release2 = await strapi2.
|
|
801
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
649
802
|
if (!release2) {
|
|
650
803
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
651
804
|
}
|
|
@@ -655,7 +808,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
655
808
|
const { entry, type } = action;
|
|
656
809
|
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
657
810
|
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
658
|
-
const releaseAction2 = await strapi2.
|
|
811
|
+
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
659
812
|
data: {
|
|
660
813
|
type,
|
|
661
814
|
contentType: entry.contentType,
|
|
@@ -668,41 +821,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
668
821
|
},
|
|
669
822
|
release: releaseId
|
|
670
823
|
},
|
|
671
|
-
populate: { release: {
|
|
824
|
+
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
672
825
|
});
|
|
673
826
|
this.updateReleaseStatus(releaseId);
|
|
674
827
|
return releaseAction2;
|
|
675
828
|
},
|
|
676
829
|
async findActions(releaseId, query) {
|
|
677
|
-
const release2 = await strapi2.
|
|
678
|
-
|
|
679
|
-
select: ["id"]
|
|
830
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
831
|
+
fields: ["id"]
|
|
680
832
|
});
|
|
681
833
|
if (!release2) {
|
|
682
834
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
683
835
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
query ?? {}
|
|
687
|
-
);
|
|
688
|
-
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
689
|
-
...dbQuery,
|
|
836
|
+
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
837
|
+
...query,
|
|
690
838
|
populate: {
|
|
691
839
|
entry: {
|
|
692
840
|
populate: "*"
|
|
693
841
|
}
|
|
694
842
|
},
|
|
695
|
-
|
|
843
|
+
filters: {
|
|
696
844
|
release: releaseId
|
|
697
845
|
}
|
|
698
846
|
});
|
|
699
847
|
},
|
|
700
848
|
async countActions(query) {
|
|
701
|
-
|
|
702
|
-
RELEASE_ACTION_MODEL_UID,
|
|
703
|
-
query ?? {}
|
|
704
|
-
);
|
|
705
|
-
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
849
|
+
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
706
850
|
},
|
|
707
851
|
async groupActions(actions, groupBy) {
|
|
708
852
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -783,11 +927,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
783
927
|
return componentsMap;
|
|
784
928
|
},
|
|
785
929
|
async delete(releaseId) {
|
|
786
|
-
const release2 = await strapi2.
|
|
787
|
-
where: { id: releaseId },
|
|
930
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
788
931
|
populate: {
|
|
789
932
|
actions: {
|
|
790
|
-
|
|
933
|
+
fields: ["id"]
|
|
791
934
|
}
|
|
792
935
|
}
|
|
793
936
|
});
|
|
@@ -805,13 +948,9 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
805
948
|
}
|
|
806
949
|
}
|
|
807
950
|
});
|
|
808
|
-
await strapi2.
|
|
809
|
-
where: {
|
|
810
|
-
id: releaseId
|
|
811
|
-
}
|
|
812
|
-
});
|
|
951
|
+
await strapi2.entityService.delete(RELEASE_MODEL_UID, releaseId);
|
|
813
952
|
});
|
|
814
|
-
if (
|
|
953
|
+
if (release2.scheduledAt) {
|
|
815
954
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
816
955
|
await schedulingService.cancel(release2.id);
|
|
817
956
|
}
|
|
@@ -819,132 +958,71 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
819
958
|
return release2;
|
|
820
959
|
},
|
|
821
960
|
async publish(releaseId) {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
entry: {
|
|
829
|
-
select: ["id"]
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
});
|
|
835
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
961
|
+
const {
|
|
962
|
+
release: release2,
|
|
963
|
+
error
|
|
964
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
965
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
966
|
+
if (!lockedRelease) {
|
|
836
967
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
837
968
|
}
|
|
838
|
-
if (
|
|
969
|
+
if (lockedRelease.releasedAt) {
|
|
839
970
|
throw new utils.errors.ValidationError("Release already published");
|
|
840
971
|
}
|
|
841
|
-
if (
|
|
842
|
-
throw new utils.errors.ValidationError("
|
|
843
|
-
}
|
|
844
|
-
const collectionTypeActions = {};
|
|
845
|
-
const singleTypeActions = [];
|
|
846
|
-
for (const action of releaseWithPopulatedActionEntries.actions) {
|
|
847
|
-
const contentTypeUid = action.contentType;
|
|
848
|
-
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
849
|
-
if (!collectionTypeActions[contentTypeUid]) {
|
|
850
|
-
collectionTypeActions[contentTypeUid] = {
|
|
851
|
-
entriestoPublishIds: [],
|
|
852
|
-
entriesToUnpublishIds: []
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
if (action.type === "publish") {
|
|
856
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
857
|
-
} else {
|
|
858
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
859
|
-
}
|
|
860
|
-
} else {
|
|
861
|
-
singleTypeActions.push({
|
|
862
|
-
uid: contentTypeUid,
|
|
863
|
-
action: action.type,
|
|
864
|
-
id: action.entry.id
|
|
865
|
-
});
|
|
866
|
-
}
|
|
972
|
+
if (lockedRelease.status === "failed") {
|
|
973
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
867
974
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
await entityManagerService.publish(entry, uid);
|
|
877
|
-
} else {
|
|
878
|
-
await entityManagerService.unpublish(entry, uid);
|
|
879
|
-
}
|
|
880
|
-
} catch (error) {
|
|
881
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
882
|
-
} else {
|
|
883
|
-
throw error;
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
888
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
889
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
890
|
-
const entriesToPublish = await strapi2.db.query(contentTypeUid).findMany({
|
|
891
|
-
where: {
|
|
892
|
-
id: {
|
|
893
|
-
$in: entriestoPublishIds
|
|
894
|
-
}
|
|
895
|
-
},
|
|
896
|
-
populate
|
|
897
|
-
});
|
|
898
|
-
const entriesToUnpublish = await strapi2.db.query(contentTypeUid).findMany({
|
|
899
|
-
where: {
|
|
900
|
-
id: {
|
|
901
|
-
$in: entriesToUnpublishIds
|
|
902
|
-
}
|
|
903
|
-
},
|
|
904
|
-
populate
|
|
905
|
-
});
|
|
906
|
-
if (entriesToPublish.length > 0) {
|
|
907
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
975
|
+
try {
|
|
976
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
977
|
+
const { collectionTypeActions, singleTypeActions } = await getFormattedActions(
|
|
978
|
+
releaseId
|
|
979
|
+
);
|
|
980
|
+
await strapi2.db.transaction(async () => {
|
|
981
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
982
|
+
await publishSingleTypeAction(uid, action, id);
|
|
908
983
|
}
|
|
909
|
-
|
|
910
|
-
|
|
984
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
985
|
+
const uid = contentTypeUid;
|
|
986
|
+
await publishCollectionTypeAction(
|
|
987
|
+
uid,
|
|
988
|
+
collectionTypeActions[uid].entriesToPublishIds,
|
|
989
|
+
collectionTypeActions[uid].entriesToUnpublishIds
|
|
990
|
+
);
|
|
911
991
|
}
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
actions: {
|
|
921
|
-
count: true
|
|
992
|
+
});
|
|
993
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
994
|
+
where: {
|
|
995
|
+
id: releaseId
|
|
996
|
+
},
|
|
997
|
+
data: {
|
|
998
|
+
status: "done",
|
|
999
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
922
1000
|
}
|
|
923
|
-
}
|
|
924
|
-
});
|
|
925
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
1001
|
+
});
|
|
926
1002
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
927
1003
|
isPublished: true,
|
|
928
|
-
release:
|
|
1004
|
+
release: release22
|
|
929
1005
|
});
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
} catch (error) {
|
|
934
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
1006
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
1007
|
+
return { release: release22, error: null };
|
|
1008
|
+
} catch (error2) {
|
|
935
1009
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
936
1010
|
isPublished: false,
|
|
937
|
-
error
|
|
1011
|
+
error: error2
|
|
938
1012
|
});
|
|
939
|
-
|
|
940
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
941
|
-
where: { id: releaseId },
|
|
942
|
-
data: {
|
|
1013
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
943
1014
|
status: "failed"
|
|
944
|
-
}
|
|
945
|
-
|
|
1015
|
+
}).transacting(trx).execute();
|
|
1016
|
+
return {
|
|
1017
|
+
release: null,
|
|
1018
|
+
error: error2
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
if (error) {
|
|
946
1023
|
throw error;
|
|
947
1024
|
}
|
|
1025
|
+
return release2;
|
|
948
1026
|
},
|
|
949
1027
|
async updateAction(actionId, releaseId, update) {
|
|
950
1028
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -1031,13 +1109,16 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1031
1109
|
}
|
|
1032
1110
|
};
|
|
1033
1111
|
};
|
|
1112
|
+
class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
1113
|
+
constructor(message) {
|
|
1114
|
+
super(message);
|
|
1115
|
+
this.name = "AlreadyOnReleaseError";
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1034
1118
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1035
1119
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1036
|
-
const release2 = await strapi2.
|
|
1037
|
-
|
|
1038
|
-
id: releaseId
|
|
1039
|
-
},
|
|
1040
|
-
populate: { actions: { populate: { entry: { select: ["id"] } } } }
|
|
1120
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
1121
|
+
populate: { actions: { populate: { entry: { fields: ["id"] } } } }
|
|
1041
1122
|
});
|
|
1042
1123
|
if (!release2) {
|
|
1043
1124
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -1046,7 +1127,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1046
1127
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1047
1128
|
);
|
|
1048
1129
|
if (isEntryInRelease) {
|
|
1049
|
-
throw new
|
|
1130
|
+
throw new AlreadyOnReleaseError(
|
|
1050
1131
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1051
1132
|
);
|
|
1052
1133
|
}
|
|
@@ -1056,9 +1137,17 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1056
1137
|
if (!contentType) {
|
|
1057
1138
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1058
1139
|
}
|
|
1140
|
+
if (!contentType.options?.draftAndPublish) {
|
|
1141
|
+
throw new utils.errors.ValidationError(
|
|
1142
|
+
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1059
1145
|
},
|
|
1060
1146
|
async validatePendingReleasesLimit() {
|
|
1061
|
-
const maximumPendingReleases =
|
|
1147
|
+
const maximumPendingReleases = (
|
|
1148
|
+
// @ts-expect-error - options is not typed into features
|
|
1149
|
+
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1150
|
+
);
|
|
1062
1151
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1063
1152
|
filters: {
|
|
1064
1153
|
releasedAt: {
|
|
@@ -1071,8 +1160,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1071
1160
|
}
|
|
1072
1161
|
},
|
|
1073
1162
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1074
|
-
const pendingReleases = await strapi2.
|
|
1075
|
-
|
|
1163
|
+
const pendingReleases = await strapi2.entityService.findMany(RELEASE_MODEL_UID, {
|
|
1164
|
+
filters: {
|
|
1076
1165
|
releasedAt: {
|
|
1077
1166
|
$null: true
|
|
1078
1167
|
},
|
|
@@ -1146,7 +1235,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1146
1235
|
const services = {
|
|
1147
1236
|
release: createReleaseService,
|
|
1148
1237
|
"release-validation": createReleaseValidationService,
|
|
1149
|
-
|
|
1238
|
+
scheduling: createSchedulingService
|
|
1150
1239
|
};
|
|
1151
1240
|
const RELEASE_SCHEMA = yup__namespace.object().shape({
|
|
1152
1241
|
name: yup__namespace.string().trim().required(),
|
|
@@ -1199,7 +1288,7 @@ const releaseController = {
|
|
|
1199
1288
|
}
|
|
1200
1289
|
};
|
|
1201
1290
|
});
|
|
1202
|
-
const pendingReleasesCount = await strapi.
|
|
1291
|
+
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1203
1292
|
where: {
|
|
1204
1293
|
releasedAt: null
|
|
1205
1294
|
}
|
|
@@ -1322,6 +1411,38 @@ const releaseActionController = {
|
|
|
1322
1411
|
data: releaseAction2
|
|
1323
1412
|
};
|
|
1324
1413
|
},
|
|
1414
|
+
async createMany(ctx) {
|
|
1415
|
+
const releaseId = ctx.params.releaseId;
|
|
1416
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1417
|
+
await Promise.all(
|
|
1418
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1419
|
+
);
|
|
1420
|
+
const releaseService = getService("release", { strapi });
|
|
1421
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1422
|
+
const releaseActions2 = await Promise.all(
|
|
1423
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1424
|
+
try {
|
|
1425
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1426
|
+
return action;
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1429
|
+
return null;
|
|
1430
|
+
}
|
|
1431
|
+
throw error;
|
|
1432
|
+
}
|
|
1433
|
+
})
|
|
1434
|
+
);
|
|
1435
|
+
return releaseActions2;
|
|
1436
|
+
});
|
|
1437
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1438
|
+
ctx.body = {
|
|
1439
|
+
data: newReleaseActions,
|
|
1440
|
+
meta: {
|
|
1441
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1442
|
+
totalEntries: releaseActions.length
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
},
|
|
1325
1446
|
async findMany(ctx) {
|
|
1326
1447
|
const releaseId = ctx.params.releaseId;
|
|
1327
1448
|
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
@@ -1345,7 +1466,7 @@ const releaseActionController = {
|
|
|
1345
1466
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1346
1467
|
return acc;
|
|
1347
1468
|
}, {});
|
|
1348
|
-
const sanitizedResults = await utils.
|
|
1469
|
+
const sanitizedResults = await utils.mapAsync(results, async (action) => ({
|
|
1349
1470
|
...action,
|
|
1350
1471
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1351
1472
|
}));
|
|
@@ -1507,6 +1628,22 @@ const releaseAction = {
|
|
|
1507
1628
|
]
|
|
1508
1629
|
}
|
|
1509
1630
|
},
|
|
1631
|
+
{
|
|
1632
|
+
method: "POST",
|
|
1633
|
+
path: "/:releaseId/actions/bulk",
|
|
1634
|
+
handler: "release-action.createMany",
|
|
1635
|
+
config: {
|
|
1636
|
+
policies: [
|
|
1637
|
+
"admin::isAuthenticatedAdmin",
|
|
1638
|
+
{
|
|
1639
|
+
name: "admin::hasPermissions",
|
|
1640
|
+
config: {
|
|
1641
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
]
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1510
1647
|
{
|
|
1511
1648
|
method: "GET",
|
|
1512
1649
|
path: "/:releaseId/actions",
|
|
@@ -1561,8 +1698,9 @@ const routes = {
|
|
|
1561
1698
|
release,
|
|
1562
1699
|
"release-action": releaseAction
|
|
1563
1700
|
};
|
|
1701
|
+
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1564
1702
|
const getPlugin = () => {
|
|
1565
|
-
if (
|
|
1703
|
+
if (features.isEnabled("cms-content-releases")) {
|
|
1566
1704
|
return {
|
|
1567
1705
|
register,
|
|
1568
1706
|
bootstrap,
|
|
@@ -1574,6 +1712,9 @@ const getPlugin = () => {
|
|
|
1574
1712
|
};
|
|
1575
1713
|
}
|
|
1576
1714
|
return {
|
|
1715
|
+
// Always return register, it handles its own feature check
|
|
1716
|
+
register,
|
|
1717
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1577
1718
|
contentTypes
|
|
1578
1719
|
};
|
|
1579
1720
|
};
|