@strapi/content-releases 0.0.0-experimental.d8a676a242377cee820b59b21a05d47290d9ac73 → 0.0.0-experimental.d954d57341a6623992a0d211daaec8e245c3517d
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-p8aKBitd.js → App-CqbuK4M6.js} +426 -427
- package/dist/_chunks/App-CqbuK4M6.js.map +1 -0
- package/dist/_chunks/{App-bpzO2Ljh.mjs → App-Do-Rnv0A.mjs} +406 -406
- package/dist/_chunks/App-Do-Rnv0A.mjs.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
- package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
- package/dist/_chunks/{en-WuuhP6Bn.mjs → en-B9Ur3VsE.mjs} +11 -3
- package/dist/_chunks/en-B9Ur3VsE.mjs.map +1 -0
- package/dist/_chunks/{en-gcJJ5htG.js → en-DtFJ5ViE.js} +11 -3
- package/dist/_chunks/en-DtFJ5ViE.js.map +1 -0
- package/dist/_chunks/{index-AECgcaDa.mjs → index-D_pgdqQL.mjs} +244 -247
- package/dist/_chunks/index-D_pgdqQL.mjs.map +1 -0
- package/dist/_chunks/{index-fP3qoWZ4.js → index-Tedsw4GC.js} +244 -249
- package/dist/_chunks/index-Tedsw4GC.js.map +1 -0
- package/dist/admin/index.js +1 -15
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +2 -16
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/CMReleasesContainer.d.ts +22 -0
- package/dist/admin/src/components/RelativeTime.d.ts +28 -0
- package/dist/admin/src/components/ReleaseAction.d.ts +3 -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/ReleaseListCell.d.ts +0 -0
- package/dist/admin/src/components/ReleaseModal.d.ts +17 -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/release.d.ts +105 -0
- package/dist/admin/src/store/hooks.d.ts +7 -0
- package/dist/admin/src/utils/api.d.ts +6 -0
- package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
- package/dist/admin/src/utils/time.d.ts +1 -0
- package/dist/server/index.js +358 -237
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +359 -237
- 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 +20 -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 +12 -0
- package/dist/server/src/controllers/release.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release-action.d.ts +8 -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 +2096 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/migrations/index.d.ts +13 -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 +182 -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 +29 -36
- package/dist/_chunks/App-bpzO2Ljh.mjs.map +0 -1
- package/dist/_chunks/App-p8aKBitd.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-AECgcaDa.mjs.map +0 -1
- package/dist/_chunks/index-fP3qoWZ4.js.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -3,7 +3,6 @@ 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");
|
|
7
6
|
const nodeSchedule = require("node-schedule");
|
|
8
7
|
const yup = require("yup");
|
|
9
8
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -27,7 +26,6 @@ function _interopNamespace(e) {
|
|
|
27
26
|
}
|
|
28
27
|
const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
|
|
29
28
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
30
|
-
const EE__default = /* @__PURE__ */ _interopDefault(EE);
|
|
31
29
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
32
30
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
33
31
|
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
@@ -78,16 +76,19 @@ const ACTIONS = [
|
|
|
78
76
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
79
77
|
RELEASES_PUBLISH: "releases.publish"
|
|
80
78
|
};
|
|
81
|
-
const getService = (name, { strapi: strapi2 }
|
|
79
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
82
80
|
return strapi2.plugin("content-releases").service(name);
|
|
83
81
|
};
|
|
84
|
-
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 }
|
|
82
|
+
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 }) => {
|
|
85
83
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
86
84
|
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
87
|
-
const entry = await strapi2.
|
|
85
|
+
const entry = await strapi2.db.query(contentTypeUid).findOne({
|
|
86
|
+
where: { id: entryId },
|
|
87
|
+
populate
|
|
88
|
+
});
|
|
88
89
|
return entry;
|
|
89
90
|
};
|
|
90
|
-
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }
|
|
91
|
+
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
91
92
|
try {
|
|
92
93
|
await strapi2.entityValidator.validateEntityCreation(
|
|
93
94
|
strapi2.getModel(contentTypeUid),
|
|
@@ -122,7 +123,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
122
123
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
123
124
|
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
124
125
|
if (deletedContentTypes.length) {
|
|
125
|
-
await utils.
|
|
126
|
+
await utils.async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
126
127
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
127
128
|
});
|
|
128
129
|
}
|
|
@@ -141,7 +142,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
});
|
|
144
|
-
utils.
|
|
145
|
+
utils.async.map(releasesWithoutStatus, async (release2) => {
|
|
145
146
|
const actions = release2.actions;
|
|
146
147
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
147
148
|
for (const action of notValidatedActions) {
|
|
@@ -172,7 +173,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
});
|
|
175
|
-
utils.
|
|
176
|
+
utils.async.map(publishedReleases, async (release2) => {
|
|
176
177
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
177
178
|
where: {
|
|
178
179
|
id: release2.id
|
|
@@ -189,7 +190,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
189
190
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
190
191
|
);
|
|
191
192
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
192
|
-
utils.
|
|
193
|
+
utils.async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
193
194
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
194
195
|
const contentType = contentTypes2[contentTypeUID];
|
|
195
196
|
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -202,7 +203,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
202
203
|
release: true
|
|
203
204
|
}
|
|
204
205
|
});
|
|
205
|
-
await utils.
|
|
206
|
+
await utils.async.map(actions, async (action) => {
|
|
206
207
|
if (action.entry && action.release) {
|
|
207
208
|
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
208
209
|
strapi
|
|
@@ -225,7 +226,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
225
226
|
});
|
|
226
227
|
}
|
|
227
228
|
}).then(() => {
|
|
228
|
-
utils.
|
|
229
|
+
utils.async.map(releasesAffected, async (releaseId) => {
|
|
229
230
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
230
231
|
});
|
|
231
232
|
});
|
|
@@ -235,13 +236,16 @@ async function disableContentTypeLocalized({ oldContentTypes, contentTypes: cont
|
|
|
235
236
|
if (!oldContentTypes) {
|
|
236
237
|
return;
|
|
237
238
|
}
|
|
239
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
240
|
+
if (!i18nPlugin) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
238
243
|
for (const uid in contentTypes2) {
|
|
239
244
|
if (!oldContentTypes[uid]) {
|
|
240
245
|
continue;
|
|
241
246
|
}
|
|
242
247
|
const oldContentType = oldContentTypes[uid];
|
|
243
248
|
const contentType = contentTypes2[uid];
|
|
244
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
245
249
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
246
250
|
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
247
251
|
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -254,13 +258,16 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
254
258
|
if (!oldContentTypes) {
|
|
255
259
|
return;
|
|
256
260
|
}
|
|
261
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
262
|
+
if (!i18nPlugin) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
257
265
|
for (const uid in contentTypes2) {
|
|
258
266
|
if (!oldContentTypes[uid]) {
|
|
259
267
|
continue;
|
|
260
268
|
}
|
|
261
269
|
const oldContentType = oldContentTypes[uid];
|
|
262
270
|
const contentType = contentTypes2[uid];
|
|
263
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
264
271
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
265
272
|
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
266
273
|
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
@@ -271,11 +278,10 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
271
278
|
}
|
|
272
279
|
}
|
|
273
280
|
}
|
|
274
|
-
const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
|
|
275
281
|
const register = async ({ strapi: strapi2 }) => {
|
|
276
|
-
if (features
|
|
277
|
-
await strapi2.admin
|
|
278
|
-
strapi2.hook("strapi::content-types.beforeSync").register(
|
|
282
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
283
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
284
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
279
285
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
280
286
|
}
|
|
281
287
|
if (strapi2.plugin("graphql")) {
|
|
@@ -284,9 +290,8 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
284
290
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
285
291
|
}
|
|
286
292
|
};
|
|
287
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
288
293
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
289
|
-
if (features
|
|
294
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
290
295
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
291
296
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
292
297
|
);
|
|
@@ -345,9 +350,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
345
350
|
actions: {
|
|
346
351
|
target_type: model.uid,
|
|
347
352
|
target_id: {
|
|
348
|
-
$in: entriesToDelete.map(
|
|
349
|
-
(entry) => entry.id
|
|
350
|
-
)
|
|
353
|
+
$in: entriesToDelete.map((entry) => entry.id)
|
|
351
354
|
}
|
|
352
355
|
}
|
|
353
356
|
}
|
|
@@ -374,13 +377,9 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
374
377
|
try {
|
|
375
378
|
const { model, result } = event;
|
|
376
379
|
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
377
|
-
const isEntryValid = await getEntryValidStatus(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
{
|
|
381
|
-
strapi: strapi2
|
|
382
|
-
}
|
|
383
|
-
);
|
|
380
|
+
const isEntryValid = await getEntryValidStatus(model.uid, result, {
|
|
381
|
+
strapi: strapi2
|
|
382
|
+
});
|
|
384
383
|
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
385
384
|
where: {
|
|
386
385
|
target_type: model.uid,
|
|
@@ -407,27 +406,23 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
407
406
|
}
|
|
408
407
|
}
|
|
409
408
|
});
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
});
|
|
420
|
-
}
|
|
409
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
410
|
+
strapi2.log.error(
|
|
411
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
412
|
+
);
|
|
413
|
+
throw err;
|
|
414
|
+
});
|
|
415
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
416
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
417
|
+
});
|
|
421
418
|
}
|
|
422
419
|
};
|
|
423
420
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
job.cancel();
|
|
430
|
-
}
|
|
421
|
+
const scheduledJobs = getService("scheduling", {
|
|
422
|
+
strapi: strapi2
|
|
423
|
+
}).getAll();
|
|
424
|
+
for (const [, job] of scheduledJobs) {
|
|
425
|
+
job.cancel();
|
|
431
426
|
}
|
|
432
427
|
};
|
|
433
428
|
const schema$1 = {
|
|
@@ -552,6 +547,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
552
547
|
release: release2
|
|
553
548
|
});
|
|
554
549
|
};
|
|
550
|
+
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
551
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
552
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
553
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
554
|
+
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
555
|
+
try {
|
|
556
|
+
if (actionType === "publish") {
|
|
557
|
+
await entityManagerService.publish(entry, uid);
|
|
558
|
+
} else {
|
|
559
|
+
await entityManagerService.unpublish(entry, uid);
|
|
560
|
+
}
|
|
561
|
+
} catch (error) {
|
|
562
|
+
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
563
|
+
;
|
|
564
|
+
else {
|
|
565
|
+
throw error;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
570
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
571
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
572
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
573
|
+
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
574
|
+
filters: {
|
|
575
|
+
id: {
|
|
576
|
+
$in: entriesToPublishIds
|
|
577
|
+
}
|
|
578
|
+
},
|
|
579
|
+
populate
|
|
580
|
+
});
|
|
581
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
582
|
+
filters: {
|
|
583
|
+
id: {
|
|
584
|
+
$in: entriestoUnpublishIds
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
populate
|
|
588
|
+
});
|
|
589
|
+
if (entriesToPublish.length > 0) {
|
|
590
|
+
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
591
|
+
}
|
|
592
|
+
if (entriesToUnpublish.length > 0) {
|
|
593
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
const getFormattedActions = async (releaseId) => {
|
|
597
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
598
|
+
where: {
|
|
599
|
+
release: {
|
|
600
|
+
id: releaseId
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
populate: {
|
|
604
|
+
entry: {
|
|
605
|
+
fields: ["id"]
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
if (actions.length === 0) {
|
|
610
|
+
throw new utils.errors.ValidationError("No entries to publish");
|
|
611
|
+
}
|
|
612
|
+
const collectionTypeActions = {};
|
|
613
|
+
const singleTypeActions = [];
|
|
614
|
+
for (const action of actions) {
|
|
615
|
+
const contentTypeUid = action.contentType;
|
|
616
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
617
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
618
|
+
collectionTypeActions[contentTypeUid] = {
|
|
619
|
+
entriesToPublishIds: [],
|
|
620
|
+
entriesToUnpublishIds: []
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
if (action.type === "publish") {
|
|
624
|
+
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
625
|
+
} else {
|
|
626
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
627
|
+
}
|
|
628
|
+
} else {
|
|
629
|
+
singleTypeActions.push({
|
|
630
|
+
uid: contentTypeUid,
|
|
631
|
+
action: action.type,
|
|
632
|
+
id: action.entry.id
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return { collectionTypeActions, singleTypeActions };
|
|
637
|
+
};
|
|
555
638
|
return {
|
|
556
639
|
async create(releaseData, { user }) {
|
|
557
640
|
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
@@ -565,13 +648,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
565
648
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
566
649
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
567
650
|
]);
|
|
568
|
-
const release2 = await strapi2.
|
|
651
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
569
652
|
data: {
|
|
570
653
|
...releaseWithCreatorFields,
|
|
571
654
|
status: "empty"
|
|
572
655
|
}
|
|
573
656
|
});
|
|
574
|
-
if (
|
|
657
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
575
658
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
576
659
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
577
660
|
}
|
|
@@ -579,28 +662,36 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
579
662
|
return release2;
|
|
580
663
|
},
|
|
581
664
|
async findOne(id, query = {}) {
|
|
582
|
-
const
|
|
583
|
-
|
|
665
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
666
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
667
|
+
...dbQuery,
|
|
668
|
+
where: { id }
|
|
584
669
|
});
|
|
585
670
|
return release2;
|
|
586
671
|
},
|
|
587
672
|
findPage(query) {
|
|
588
|
-
|
|
589
|
-
|
|
673
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
674
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
675
|
+
...dbQuery,
|
|
590
676
|
populate: {
|
|
591
677
|
actions: {
|
|
592
|
-
// @ts-expect-error Ignore missing properties
|
|
593
678
|
count: true
|
|
594
679
|
}
|
|
595
680
|
}
|
|
596
681
|
});
|
|
597
682
|
},
|
|
598
|
-
async findManyWithContentTypeEntryAttached(contentTypeUid,
|
|
683
|
+
async findManyWithContentTypeEntryAttached(contentTypeUid, entriesIds) {
|
|
684
|
+
let entries = entriesIds;
|
|
685
|
+
if (!Array.isArray(entriesIds)) {
|
|
686
|
+
entries = [entriesIds];
|
|
687
|
+
}
|
|
599
688
|
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
600
689
|
where: {
|
|
601
690
|
actions: {
|
|
602
691
|
target_type: contentTypeUid,
|
|
603
|
-
target_id:
|
|
692
|
+
target_id: {
|
|
693
|
+
$in: entries
|
|
694
|
+
}
|
|
604
695
|
},
|
|
605
696
|
releasedAt: {
|
|
606
697
|
$null: true
|
|
@@ -611,18 +702,25 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
611
702
|
actions: {
|
|
612
703
|
where: {
|
|
613
704
|
target_type: contentTypeUid,
|
|
614
|
-
target_id:
|
|
705
|
+
target_id: {
|
|
706
|
+
$in: entries
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
populate: {
|
|
710
|
+
entry: {
|
|
711
|
+
select: ["id"]
|
|
712
|
+
}
|
|
615
713
|
}
|
|
616
714
|
}
|
|
617
715
|
}
|
|
618
716
|
});
|
|
619
717
|
return releases.map((release2) => {
|
|
620
718
|
if (release2.actions?.length) {
|
|
621
|
-
const
|
|
719
|
+
const actionsForEntry = release2.actions;
|
|
622
720
|
delete release2.actions;
|
|
623
721
|
return {
|
|
624
722
|
...release2,
|
|
625
|
-
|
|
723
|
+
actions: actionsForEntry
|
|
626
724
|
};
|
|
627
725
|
}
|
|
628
726
|
return release2;
|
|
@@ -681,28 +779,22 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
681
779
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
682
780
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
683
781
|
]);
|
|
684
|
-
const release2 = await strapi2.
|
|
782
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
685
783
|
if (!release2) {
|
|
686
784
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
687
785
|
}
|
|
688
786
|
if (release2.releasedAt) {
|
|
689
787
|
throw new utils.errors.ValidationError("Release already published");
|
|
690
788
|
}
|
|
691
|
-
const updatedRelease = await strapi2.
|
|
692
|
-
|
|
693
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
694
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
695
|
-
*/
|
|
696
|
-
// @ts-expect-error see above
|
|
789
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
790
|
+
where: { id },
|
|
697
791
|
data: releaseWithCreatorFields
|
|
698
792
|
});
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
schedulingService.cancel(id);
|
|
705
|
-
}
|
|
793
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
794
|
+
if (releaseData.scheduledAt) {
|
|
795
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
796
|
+
} else if (release2.scheduledAt) {
|
|
797
|
+
schedulingService.cancel(id);
|
|
706
798
|
}
|
|
707
799
|
this.updateReleaseStatus(id);
|
|
708
800
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
@@ -716,7 +808,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
716
808
|
validateEntryContentType(action.entry.contentType),
|
|
717
809
|
validateUniqueEntry(releaseId, action)
|
|
718
810
|
]);
|
|
719
|
-
const release2 = await strapi2.
|
|
811
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
720
812
|
if (!release2) {
|
|
721
813
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
722
814
|
}
|
|
@@ -726,7 +818,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
726
818
|
const { entry, type } = action;
|
|
727
819
|
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
728
820
|
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
729
|
-
const releaseAction2 = await strapi2.
|
|
821
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
730
822
|
data: {
|
|
731
823
|
type,
|
|
732
824
|
contentType: entry.contentType,
|
|
@@ -739,32 +831,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
739
831
|
},
|
|
740
832
|
release: releaseId
|
|
741
833
|
},
|
|
742
|
-
populate: { release: {
|
|
834
|
+
populate: { release: { select: ["id"] }, entry: { select: ["id"] } }
|
|
743
835
|
});
|
|
744
836
|
this.updateReleaseStatus(releaseId);
|
|
745
837
|
return releaseAction2;
|
|
746
838
|
},
|
|
747
839
|
async findActions(releaseId, query) {
|
|
748
|
-
const release2 = await strapi2.
|
|
749
|
-
|
|
840
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
841
|
+
where: { id: releaseId },
|
|
842
|
+
select: ["id"]
|
|
750
843
|
});
|
|
751
844
|
if (!release2) {
|
|
752
845
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
753
846
|
}
|
|
754
|
-
|
|
755
|
-
|
|
847
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
848
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
849
|
+
...dbQuery,
|
|
756
850
|
populate: {
|
|
757
851
|
entry: {
|
|
758
852
|
populate: "*"
|
|
759
853
|
}
|
|
760
854
|
},
|
|
761
|
-
|
|
855
|
+
where: {
|
|
762
856
|
release: releaseId
|
|
763
857
|
}
|
|
764
858
|
});
|
|
765
859
|
},
|
|
766
860
|
async countActions(query) {
|
|
767
|
-
|
|
861
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
862
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
768
863
|
},
|
|
769
864
|
async groupActions(actions, groupBy) {
|
|
770
865
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -773,9 +868,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
773
868
|
}
|
|
774
869
|
return acc;
|
|
775
870
|
}, []);
|
|
776
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
777
|
-
contentTypeUids
|
|
778
|
-
);
|
|
871
|
+
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(contentTypeUids);
|
|
779
872
|
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
780
873
|
const formattedData = actions.map((action) => {
|
|
781
874
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
@@ -845,10 +938,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
845
938
|
return componentsMap;
|
|
846
939
|
},
|
|
847
940
|
async delete(releaseId) {
|
|
848
|
-
const release2 = await strapi2.
|
|
941
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
942
|
+
where: { id: releaseId },
|
|
849
943
|
populate: {
|
|
850
944
|
actions: {
|
|
851
|
-
|
|
945
|
+
select: ["id"]
|
|
852
946
|
}
|
|
853
947
|
}
|
|
854
948
|
});
|
|
@@ -866,9 +960,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
866
960
|
}
|
|
867
961
|
}
|
|
868
962
|
});
|
|
869
|
-
await strapi2.
|
|
963
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
964
|
+
where: {
|
|
965
|
+
id: releaseId
|
|
966
|
+
}
|
|
967
|
+
});
|
|
870
968
|
});
|
|
871
|
-
if (
|
|
969
|
+
if (release2.scheduledAt) {
|
|
872
970
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
873
971
|
await schedulingService.cancel(release2.id);
|
|
874
972
|
}
|
|
@@ -876,145 +974,69 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
876
974
|
return release2;
|
|
877
975
|
},
|
|
878
976
|
async publish(releaseId) {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
actions: {
|
|
886
|
-
populate: {
|
|
887
|
-
entry: {
|
|
888
|
-
fields: ["id"]
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
);
|
|
895
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
977
|
+
const {
|
|
978
|
+
release: release2,
|
|
979
|
+
error
|
|
980
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
981
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
982
|
+
if (!lockedRelease) {
|
|
896
983
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
897
984
|
}
|
|
898
|
-
if (
|
|
985
|
+
if (lockedRelease.releasedAt) {
|
|
899
986
|
throw new utils.errors.ValidationError("Release already published");
|
|
900
987
|
}
|
|
901
|
-
if (
|
|
902
|
-
throw new utils.errors.ValidationError("
|
|
988
|
+
if (lockedRelease.status === "failed") {
|
|
989
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
903
990
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
collectionTypeActions[contentTypeUid] = {
|
|
911
|
-
entriestoPublishIds: [],
|
|
912
|
-
entriesToUnpublishIds: []
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
if (action.type === "publish") {
|
|
916
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
917
|
-
} else {
|
|
918
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
919
|
-
}
|
|
920
|
-
} else {
|
|
921
|
-
singleTypeActions.push({
|
|
922
|
-
uid: contentTypeUid,
|
|
923
|
-
action: action.type,
|
|
924
|
-
id: action.entry.id
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
929
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
930
|
-
await strapi2.db.transaction(async () => {
|
|
931
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
932
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
933
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
934
|
-
try {
|
|
935
|
-
if (action === "publish") {
|
|
936
|
-
await entityManagerService.publish(entry, uid);
|
|
937
|
-
} else {
|
|
938
|
-
await entityManagerService.unpublish(entry, uid);
|
|
939
|
-
}
|
|
940
|
-
} catch (error) {
|
|
941
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
942
|
-
} else {
|
|
943
|
-
throw error;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
948
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
949
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
950
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
951
|
-
contentTypeUid,
|
|
952
|
-
{
|
|
953
|
-
filters: {
|
|
954
|
-
id: {
|
|
955
|
-
$in: entriestoPublishIds
|
|
956
|
-
}
|
|
957
|
-
},
|
|
958
|
-
populate
|
|
959
|
-
}
|
|
960
|
-
);
|
|
961
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
962
|
-
contentTypeUid,
|
|
963
|
-
{
|
|
964
|
-
filters: {
|
|
965
|
-
id: {
|
|
966
|
-
$in: entriesToUnpublishIds
|
|
967
|
-
}
|
|
968
|
-
},
|
|
969
|
-
populate
|
|
970
|
-
}
|
|
971
|
-
);
|
|
972
|
-
if (entriesToPublish.length > 0) {
|
|
973
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
991
|
+
try {
|
|
992
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
993
|
+
const { collectionTypeActions, singleTypeActions } = await getFormattedActions(releaseId);
|
|
994
|
+
await strapi2.db.transaction(async () => {
|
|
995
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
996
|
+
await publishSingleTypeAction(uid, action, id);
|
|
974
997
|
}
|
|
975
|
-
|
|
976
|
-
|
|
998
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
999
|
+
const uid = contentTypeUid;
|
|
1000
|
+
await publishCollectionTypeAction(
|
|
1001
|
+
uid,
|
|
1002
|
+
collectionTypeActions[uid].entriesToPublishIds,
|
|
1003
|
+
collectionTypeActions[uid].entriesToUnpublishIds
|
|
1004
|
+
);
|
|
977
1005
|
}
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
987
|
-
},
|
|
988
|
-
populate: {
|
|
989
|
-
actions: {
|
|
990
|
-
// @ts-expect-error is not expecting count but it is working
|
|
991
|
-
count: true
|
|
1006
|
+
});
|
|
1007
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1008
|
+
where: {
|
|
1009
|
+
id: releaseId
|
|
1010
|
+
},
|
|
1011
|
+
data: {
|
|
1012
|
+
status: "done",
|
|
1013
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
992
1014
|
}
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
1015
|
+
});
|
|
996
1016
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
997
1017
|
isPublished: true,
|
|
998
|
-
release:
|
|
1018
|
+
release: release22
|
|
999
1019
|
});
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
} catch (error) {
|
|
1004
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
1020
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
1021
|
+
return { release: release22, error: null };
|
|
1022
|
+
} catch (error2) {
|
|
1005
1023
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
1006
1024
|
isPublished: false,
|
|
1007
|
-
error
|
|
1025
|
+
error: error2
|
|
1008
1026
|
});
|
|
1009
|
-
|
|
1010
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1011
|
-
where: { id: releaseId },
|
|
1012
|
-
data: {
|
|
1027
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
1013
1028
|
status: "failed"
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1029
|
+
}).transacting(trx).execute();
|
|
1030
|
+
return {
|
|
1031
|
+
release: null,
|
|
1032
|
+
error: error2
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
1036
|
+
if (error instanceof Error) {
|
|
1016
1037
|
throw error;
|
|
1017
1038
|
}
|
|
1039
|
+
return release2;
|
|
1018
1040
|
},
|
|
1019
1041
|
async updateAction(actionId, releaseId, update) {
|
|
1020
1042
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -1101,10 +1123,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1101
1123
|
}
|
|
1102
1124
|
};
|
|
1103
1125
|
};
|
|
1126
|
+
class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
1127
|
+
constructor(message) {
|
|
1128
|
+
super(message);
|
|
1129
|
+
this.name = "AlreadyOnReleaseError";
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1104
1132
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1105
1133
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1106
|
-
const release2 = await strapi2.
|
|
1107
|
-
|
|
1134
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1135
|
+
where: {
|
|
1136
|
+
id: releaseId
|
|
1137
|
+
},
|
|
1138
|
+
populate: { actions: { populate: { entry: { select: ["id"] } } } }
|
|
1108
1139
|
});
|
|
1109
1140
|
if (!release2) {
|
|
1110
1141
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -1113,7 +1144,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1113
1144
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1114
1145
|
);
|
|
1115
1146
|
if (isEntryInRelease) {
|
|
1116
|
-
throw new
|
|
1147
|
+
throw new AlreadyOnReleaseError(
|
|
1117
1148
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1118
1149
|
);
|
|
1119
1150
|
}
|
|
@@ -1130,10 +1161,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1130
1161
|
}
|
|
1131
1162
|
},
|
|
1132
1163
|
async validatePendingReleasesLimit() {
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1136
|
-
);
|
|
1164
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1165
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1137
1166
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1138
1167
|
filters: {
|
|
1139
1168
|
releasedAt: {
|
|
@@ -1146,8 +1175,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1146
1175
|
}
|
|
1147
1176
|
},
|
|
1148
1177
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1149
|
-
const pendingReleases = await strapi2.
|
|
1150
|
-
|
|
1178
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1179
|
+
where: {
|
|
1151
1180
|
releasedAt: {
|
|
1152
1181
|
$null: true
|
|
1153
1182
|
},
|
|
@@ -1176,7 +1205,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1176
1205
|
}
|
|
1177
1206
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1178
1207
|
try {
|
|
1179
|
-
await getService("release").publish(releaseId);
|
|
1208
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1180
1209
|
} catch (error) {
|
|
1181
1210
|
}
|
|
1182
1211
|
this.cancel(releaseId);
|
|
@@ -1221,7 +1250,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1221
1250
|
const services = {
|
|
1222
1251
|
release: createReleaseService,
|
|
1223
1252
|
"release-validation": createReleaseValidationService,
|
|
1224
|
-
|
|
1253
|
+
scheduling: createSchedulingService
|
|
1225
1254
|
};
|
|
1226
1255
|
const RELEASE_SCHEMA = yup__namespace.object().shape({
|
|
1227
1256
|
name: yup__namespace.string().trim().required(),
|
|
@@ -1246,7 +1275,7 @@ const RELEASE_SCHEMA = yup__namespace.object().shape({
|
|
|
1246
1275
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1247
1276
|
const releaseController = {
|
|
1248
1277
|
async findMany(ctx) {
|
|
1249
|
-
const permissionsManager = strapi.admin
|
|
1278
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1250
1279
|
ability: ctx.state.userAbility,
|
|
1251
1280
|
model: RELEASE_MODEL_UID
|
|
1252
1281
|
});
|
|
@@ -1274,7 +1303,7 @@ const releaseController = {
|
|
|
1274
1303
|
}
|
|
1275
1304
|
};
|
|
1276
1305
|
});
|
|
1277
|
-
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1306
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1278
1307
|
where: {
|
|
1279
1308
|
releasedAt: null
|
|
1280
1309
|
}
|
|
@@ -1296,7 +1325,7 @@ const releaseController = {
|
|
|
1296
1325
|
});
|
|
1297
1326
|
const sanitizedRelease = {
|
|
1298
1327
|
...release2,
|
|
1299
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1328
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1300
1329
|
};
|
|
1301
1330
|
const data = {
|
|
1302
1331
|
...sanitizedRelease,
|
|
@@ -1308,19 +1337,48 @@ const releaseController = {
|
|
|
1308
1337
|
};
|
|
1309
1338
|
ctx.body = { data };
|
|
1310
1339
|
},
|
|
1340
|
+
async mapEntriesToReleases(ctx) {
|
|
1341
|
+
const { contentTypeUid, entriesIds } = ctx.query;
|
|
1342
|
+
if (!contentTypeUid || !entriesIds) {
|
|
1343
|
+
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1344
|
+
}
|
|
1345
|
+
const releaseService = getService("release", { strapi });
|
|
1346
|
+
const releasesWithActions = await releaseService.findManyWithContentTypeEntryAttached(
|
|
1347
|
+
contentTypeUid,
|
|
1348
|
+
entriesIds
|
|
1349
|
+
);
|
|
1350
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1351
|
+
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1352
|
+
(acc, release2) => {
|
|
1353
|
+
release2.actions.forEach((action) => {
|
|
1354
|
+
if (!acc[action.entry.id]) {
|
|
1355
|
+
acc[action.entry.id] = [{ id: release2.id, name: release2.name }];
|
|
1356
|
+
} else {
|
|
1357
|
+
acc[action.entry.id].push({ id: release2.id, name: release2.name });
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1360
|
+
return acc;
|
|
1361
|
+
},
|
|
1362
|
+
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1363
|
+
{}
|
|
1364
|
+
);
|
|
1365
|
+
ctx.body = {
|
|
1366
|
+
data: mappedEntriesInReleases
|
|
1367
|
+
};
|
|
1368
|
+
},
|
|
1311
1369
|
async create(ctx) {
|
|
1312
1370
|
const user = ctx.state.user;
|
|
1313
1371
|
const releaseArgs = ctx.request.body;
|
|
1314
1372
|
await validateRelease(releaseArgs);
|
|
1315
1373
|
const releaseService = getService("release", { strapi });
|
|
1316
1374
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1317
|
-
const permissionsManager = strapi.admin
|
|
1375
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1318
1376
|
ability: ctx.state.userAbility,
|
|
1319
1377
|
model: RELEASE_MODEL_UID
|
|
1320
1378
|
});
|
|
1321
|
-
ctx.
|
|
1379
|
+
ctx.created({
|
|
1322
1380
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1323
|
-
};
|
|
1381
|
+
});
|
|
1324
1382
|
},
|
|
1325
1383
|
async update(ctx) {
|
|
1326
1384
|
const user = ctx.state.user;
|
|
@@ -1329,7 +1387,7 @@ const releaseController = {
|
|
|
1329
1387
|
await validateRelease(releaseArgs);
|
|
1330
1388
|
const releaseService = getService("release", { strapi });
|
|
1331
1389
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1332
|
-
const permissionsManager = strapi.admin
|
|
1390
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1333
1391
|
ability: ctx.state.userAbility,
|
|
1334
1392
|
model: RELEASE_MODEL_UID
|
|
1335
1393
|
});
|
|
@@ -1393,13 +1451,45 @@ const releaseActionController = {
|
|
|
1393
1451
|
await validateReleaseAction(releaseActionArgs);
|
|
1394
1452
|
const releaseService = getService("release", { strapi });
|
|
1395
1453
|
const releaseAction2 = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1396
|
-
ctx.
|
|
1454
|
+
ctx.created({
|
|
1397
1455
|
data: releaseAction2
|
|
1398
|
-
};
|
|
1456
|
+
});
|
|
1457
|
+
},
|
|
1458
|
+
async createMany(ctx) {
|
|
1459
|
+
const releaseId = ctx.params.releaseId;
|
|
1460
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1461
|
+
await Promise.all(
|
|
1462
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1463
|
+
);
|
|
1464
|
+
const releaseService = getService("release", { strapi });
|
|
1465
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1466
|
+
const releaseActions2 = await Promise.all(
|
|
1467
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1468
|
+
try {
|
|
1469
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1470
|
+
return action;
|
|
1471
|
+
} catch (error) {
|
|
1472
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1473
|
+
return null;
|
|
1474
|
+
}
|
|
1475
|
+
throw error;
|
|
1476
|
+
}
|
|
1477
|
+
})
|
|
1478
|
+
);
|
|
1479
|
+
return releaseActions2;
|
|
1480
|
+
});
|
|
1481
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1482
|
+
ctx.created({
|
|
1483
|
+
data: newReleaseActions,
|
|
1484
|
+
meta: {
|
|
1485
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1486
|
+
totalEntries: releaseActions.length
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1399
1489
|
},
|
|
1400
1490
|
async findMany(ctx) {
|
|
1401
1491
|
const releaseId = ctx.params.releaseId;
|
|
1402
|
-
const permissionsManager = strapi.admin
|
|
1492
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1403
1493
|
ability: ctx.state.userAbility,
|
|
1404
1494
|
model: RELEASE_ACTION_MODEL_UID
|
|
1405
1495
|
});
|
|
@@ -1413,14 +1503,14 @@ const releaseActionController = {
|
|
|
1413
1503
|
if (acc[action.contentType]) {
|
|
1414
1504
|
return acc;
|
|
1415
1505
|
}
|
|
1416
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1506
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1417
1507
|
ability: ctx.state.userAbility,
|
|
1418
1508
|
model: action.contentType
|
|
1419
1509
|
});
|
|
1420
1510
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1421
1511
|
return acc;
|
|
1422
1512
|
}, {});
|
|
1423
|
-
const sanitizedResults = await utils.
|
|
1513
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1424
1514
|
...action,
|
|
1425
1515
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1426
1516
|
}));
|
|
@@ -1465,6 +1555,22 @@ const controllers = { release: releaseController, "release-action": releaseActio
|
|
|
1465
1555
|
const release = {
|
|
1466
1556
|
type: "admin",
|
|
1467
1557
|
routes: [
|
|
1558
|
+
{
|
|
1559
|
+
method: "GET",
|
|
1560
|
+
path: "/mapEntriesToReleases",
|
|
1561
|
+
handler: "release.mapEntriesToReleases",
|
|
1562
|
+
config: {
|
|
1563
|
+
policies: [
|
|
1564
|
+
"admin::isAuthenticatedAdmin",
|
|
1565
|
+
{
|
|
1566
|
+
name: "admin::hasPermissions",
|
|
1567
|
+
config: {
|
|
1568
|
+
actions: ["plugin::content-releases.read"]
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
]
|
|
1572
|
+
}
|
|
1573
|
+
},
|
|
1468
1574
|
{
|
|
1469
1575
|
method: "POST",
|
|
1470
1576
|
path: "/",
|
|
@@ -1582,6 +1688,22 @@ const releaseAction = {
|
|
|
1582
1688
|
]
|
|
1583
1689
|
}
|
|
1584
1690
|
},
|
|
1691
|
+
{
|
|
1692
|
+
method: "POST",
|
|
1693
|
+
path: "/:releaseId/actions/bulk",
|
|
1694
|
+
handler: "release-action.createMany",
|
|
1695
|
+
config: {
|
|
1696
|
+
policies: [
|
|
1697
|
+
"admin::isAuthenticatedAdmin",
|
|
1698
|
+
{
|
|
1699
|
+
name: "admin::hasPermissions",
|
|
1700
|
+
config: {
|
|
1701
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
]
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1585
1707
|
{
|
|
1586
1708
|
method: "GET",
|
|
1587
1709
|
path: "/:releaseId/actions",
|
|
@@ -1636,9 +1758,8 @@ const routes = {
|
|
|
1636
1758
|
release,
|
|
1637
1759
|
"release-action": releaseAction
|
|
1638
1760
|
};
|
|
1639
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1640
1761
|
const getPlugin = () => {
|
|
1641
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1762
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1642
1763
|
return {
|
|
1643
1764
|
register,
|
|
1644
1765
|
bootstrap,
|