@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.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { contentTypes as contentTypes$1,
|
|
1
|
+
import { contentTypes as contentTypes$1, async, setCreatorFields, errors, validateYupSchema, yup as yup$1 } from "@strapi/utils";
|
|
2
2
|
import isEqual from "lodash/isEqual";
|
|
3
3
|
import { difference, keys } from "lodash";
|
|
4
4
|
import _ from "lodash/fp";
|
|
5
|
-
import EE from "@strapi/strapi/dist/utils/ee";
|
|
6
5
|
import { scheduleJob } from "node-schedule";
|
|
7
6
|
import * as yup from "yup";
|
|
8
7
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
@@ -54,16 +53,19 @@ const ACTIONS = [
|
|
|
54
53
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
55
54
|
RELEASES_PUBLISH: "releases.publish"
|
|
56
55
|
};
|
|
57
|
-
const getService = (name, { strapi: strapi2 }
|
|
56
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
58
57
|
return strapi2.plugin("content-releases").service(name);
|
|
59
58
|
};
|
|
60
|
-
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 }
|
|
59
|
+
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 }) => {
|
|
61
60
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
62
61
|
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
63
|
-
const entry = await strapi2.
|
|
62
|
+
const entry = await strapi2.db.query(contentTypeUid).findOne({
|
|
63
|
+
where: { id: entryId },
|
|
64
|
+
populate
|
|
65
|
+
});
|
|
64
66
|
return entry;
|
|
65
67
|
};
|
|
66
|
-
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }
|
|
68
|
+
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
67
69
|
try {
|
|
68
70
|
await strapi2.entityValidator.validateEntityCreation(
|
|
69
71
|
strapi2.getModel(contentTypeUid),
|
|
@@ -98,7 +100,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
98
100
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
99
101
|
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes2)) ?? [];
|
|
100
102
|
if (deletedContentTypes.length) {
|
|
101
|
-
await
|
|
103
|
+
await async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
102
104
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
103
105
|
});
|
|
104
106
|
}
|
|
@@ -117,7 +119,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
});
|
|
120
|
-
|
|
122
|
+
async.map(releasesWithoutStatus, async (release2) => {
|
|
121
123
|
const actions = release2.actions;
|
|
122
124
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
123
125
|
for (const action of notValidatedActions) {
|
|
@@ -148,7 +150,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
});
|
|
151
|
-
|
|
153
|
+
async.map(publishedReleases, async (release2) => {
|
|
152
154
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
153
155
|
where: {
|
|
154
156
|
id: release2.id
|
|
@@ -165,7 +167,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
165
167
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
166
168
|
);
|
|
167
169
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
168
|
-
|
|
170
|
+
async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
169
171
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
170
172
|
const contentType = contentTypes2[contentTypeUID];
|
|
171
173
|
if (!isEqual(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -178,7 +180,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
178
180
|
release: true
|
|
179
181
|
}
|
|
180
182
|
});
|
|
181
|
-
await
|
|
183
|
+
await async.map(actions, async (action) => {
|
|
182
184
|
if (action.entry && action.release) {
|
|
183
185
|
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
184
186
|
strapi
|
|
@@ -201,7 +203,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
201
203
|
});
|
|
202
204
|
}
|
|
203
205
|
}).then(() => {
|
|
204
|
-
|
|
206
|
+
async.map(releasesAffected, async (releaseId) => {
|
|
205
207
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
206
208
|
});
|
|
207
209
|
});
|
|
@@ -211,13 +213,16 @@ async function disableContentTypeLocalized({ oldContentTypes, contentTypes: cont
|
|
|
211
213
|
if (!oldContentTypes) {
|
|
212
214
|
return;
|
|
213
215
|
}
|
|
216
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
217
|
+
if (!i18nPlugin) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
214
220
|
for (const uid in contentTypes2) {
|
|
215
221
|
if (!oldContentTypes[uid]) {
|
|
216
222
|
continue;
|
|
217
223
|
}
|
|
218
224
|
const oldContentType = oldContentTypes[uid];
|
|
219
225
|
const contentType = contentTypes2[uid];
|
|
220
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
221
226
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
222
227
|
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
223
228
|
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -230,13 +235,16 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
230
235
|
if (!oldContentTypes) {
|
|
231
236
|
return;
|
|
232
237
|
}
|
|
238
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
239
|
+
if (!i18nPlugin) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
233
242
|
for (const uid in contentTypes2) {
|
|
234
243
|
if (!oldContentTypes[uid]) {
|
|
235
244
|
continue;
|
|
236
245
|
}
|
|
237
246
|
const oldContentType = oldContentTypes[uid];
|
|
238
247
|
const contentType = contentTypes2[uid];
|
|
239
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
240
248
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
241
249
|
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
242
250
|
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
@@ -247,11 +255,10 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
247
255
|
}
|
|
248
256
|
}
|
|
249
257
|
}
|
|
250
|
-
const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
|
|
251
258
|
const register = async ({ strapi: strapi2 }) => {
|
|
252
|
-
if (features
|
|
253
|
-
await strapi2.admin
|
|
254
|
-
strapi2.hook("strapi::content-types.beforeSync").register(
|
|
259
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
260
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
261
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
255
262
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
256
263
|
}
|
|
257
264
|
if (strapi2.plugin("graphql")) {
|
|
@@ -260,9 +267,8 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
260
267
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
261
268
|
}
|
|
262
269
|
};
|
|
263
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
264
270
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
265
|
-
if (features
|
|
271
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
266
272
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
267
273
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
268
274
|
);
|
|
@@ -321,9 +327,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
321
327
|
actions: {
|
|
322
328
|
target_type: model.uid,
|
|
323
329
|
target_id: {
|
|
324
|
-
$in: entriesToDelete.map(
|
|
325
|
-
(entry) => entry.id
|
|
326
|
-
)
|
|
330
|
+
$in: entriesToDelete.map((entry) => entry.id)
|
|
327
331
|
}
|
|
328
332
|
}
|
|
329
333
|
}
|
|
@@ -350,13 +354,9 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
350
354
|
try {
|
|
351
355
|
const { model, result } = event;
|
|
352
356
|
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
353
|
-
const isEntryValid = await getEntryValidStatus(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
{
|
|
357
|
-
strapi: strapi2
|
|
358
|
-
}
|
|
359
|
-
);
|
|
357
|
+
const isEntryValid = await getEntryValidStatus(model.uid, result, {
|
|
358
|
+
strapi: strapi2
|
|
359
|
+
});
|
|
360
360
|
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
361
361
|
where: {
|
|
362
362
|
target_type: model.uid,
|
|
@@ -383,27 +383,23 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
385
|
});
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
});
|
|
396
|
-
}
|
|
386
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
387
|
+
strapi2.log.error(
|
|
388
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
389
|
+
);
|
|
390
|
+
throw err;
|
|
391
|
+
});
|
|
392
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
393
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
394
|
+
});
|
|
397
395
|
}
|
|
398
396
|
};
|
|
399
397
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
job.cancel();
|
|
406
|
-
}
|
|
398
|
+
const scheduledJobs = getService("scheduling", {
|
|
399
|
+
strapi: strapi2
|
|
400
|
+
}).getAll();
|
|
401
|
+
for (const [, job] of scheduledJobs) {
|
|
402
|
+
job.cancel();
|
|
407
403
|
}
|
|
408
404
|
};
|
|
409
405
|
const schema$1 = {
|
|
@@ -528,6 +524,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
528
524
|
release: release2
|
|
529
525
|
});
|
|
530
526
|
};
|
|
527
|
+
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
528
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
529
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
530
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
531
|
+
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
532
|
+
try {
|
|
533
|
+
if (actionType === "publish") {
|
|
534
|
+
await entityManagerService.publish(entry, uid);
|
|
535
|
+
} else {
|
|
536
|
+
await entityManagerService.unpublish(entry, uid);
|
|
537
|
+
}
|
|
538
|
+
} catch (error) {
|
|
539
|
+
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
540
|
+
;
|
|
541
|
+
else {
|
|
542
|
+
throw error;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
547
|
+
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
548
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
549
|
+
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
550
|
+
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
551
|
+
filters: {
|
|
552
|
+
id: {
|
|
553
|
+
$in: entriesToPublishIds
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
populate
|
|
557
|
+
});
|
|
558
|
+
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
559
|
+
filters: {
|
|
560
|
+
id: {
|
|
561
|
+
$in: entriestoUnpublishIds
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
populate
|
|
565
|
+
});
|
|
566
|
+
if (entriesToPublish.length > 0) {
|
|
567
|
+
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
568
|
+
}
|
|
569
|
+
if (entriesToUnpublish.length > 0) {
|
|
570
|
+
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
const getFormattedActions = async (releaseId) => {
|
|
574
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
575
|
+
where: {
|
|
576
|
+
release: {
|
|
577
|
+
id: releaseId
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
populate: {
|
|
581
|
+
entry: {
|
|
582
|
+
fields: ["id"]
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
if (actions.length === 0) {
|
|
587
|
+
throw new errors.ValidationError("No entries to publish");
|
|
588
|
+
}
|
|
589
|
+
const collectionTypeActions = {};
|
|
590
|
+
const singleTypeActions = [];
|
|
591
|
+
for (const action of actions) {
|
|
592
|
+
const contentTypeUid = action.contentType;
|
|
593
|
+
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
594
|
+
if (!collectionTypeActions[contentTypeUid]) {
|
|
595
|
+
collectionTypeActions[contentTypeUid] = {
|
|
596
|
+
entriesToPublishIds: [],
|
|
597
|
+
entriesToUnpublishIds: []
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
if (action.type === "publish") {
|
|
601
|
+
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
602
|
+
} else {
|
|
603
|
+
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
604
|
+
}
|
|
605
|
+
} else {
|
|
606
|
+
singleTypeActions.push({
|
|
607
|
+
uid: contentTypeUid,
|
|
608
|
+
action: action.type,
|
|
609
|
+
id: action.entry.id
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return { collectionTypeActions, singleTypeActions };
|
|
614
|
+
};
|
|
531
615
|
return {
|
|
532
616
|
async create(releaseData, { user }) {
|
|
533
617
|
const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
|
|
@@ -541,13 +625,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
541
625
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
542
626
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
543
627
|
]);
|
|
544
|
-
const release2 = await strapi2.
|
|
628
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
545
629
|
data: {
|
|
546
630
|
...releaseWithCreatorFields,
|
|
547
631
|
status: "empty"
|
|
548
632
|
}
|
|
549
633
|
});
|
|
550
|
-
if (
|
|
634
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
551
635
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
552
636
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
553
637
|
}
|
|
@@ -555,28 +639,36 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
555
639
|
return release2;
|
|
556
640
|
},
|
|
557
641
|
async findOne(id, query = {}) {
|
|
558
|
-
const
|
|
559
|
-
|
|
642
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
643
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
644
|
+
...dbQuery,
|
|
645
|
+
where: { id }
|
|
560
646
|
});
|
|
561
647
|
return release2;
|
|
562
648
|
},
|
|
563
649
|
findPage(query) {
|
|
564
|
-
|
|
565
|
-
|
|
650
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
651
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
652
|
+
...dbQuery,
|
|
566
653
|
populate: {
|
|
567
654
|
actions: {
|
|
568
|
-
// @ts-expect-error Ignore missing properties
|
|
569
655
|
count: true
|
|
570
656
|
}
|
|
571
657
|
}
|
|
572
658
|
});
|
|
573
659
|
},
|
|
574
|
-
async findManyWithContentTypeEntryAttached(contentTypeUid,
|
|
660
|
+
async findManyWithContentTypeEntryAttached(contentTypeUid, entriesIds) {
|
|
661
|
+
let entries = entriesIds;
|
|
662
|
+
if (!Array.isArray(entriesIds)) {
|
|
663
|
+
entries = [entriesIds];
|
|
664
|
+
}
|
|
575
665
|
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
576
666
|
where: {
|
|
577
667
|
actions: {
|
|
578
668
|
target_type: contentTypeUid,
|
|
579
|
-
target_id:
|
|
669
|
+
target_id: {
|
|
670
|
+
$in: entries
|
|
671
|
+
}
|
|
580
672
|
},
|
|
581
673
|
releasedAt: {
|
|
582
674
|
$null: true
|
|
@@ -587,18 +679,25 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
587
679
|
actions: {
|
|
588
680
|
where: {
|
|
589
681
|
target_type: contentTypeUid,
|
|
590
|
-
target_id:
|
|
682
|
+
target_id: {
|
|
683
|
+
$in: entries
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
populate: {
|
|
687
|
+
entry: {
|
|
688
|
+
select: ["id"]
|
|
689
|
+
}
|
|
591
690
|
}
|
|
592
691
|
}
|
|
593
692
|
}
|
|
594
693
|
});
|
|
595
694
|
return releases.map((release2) => {
|
|
596
695
|
if (release2.actions?.length) {
|
|
597
|
-
const
|
|
696
|
+
const actionsForEntry = release2.actions;
|
|
598
697
|
delete release2.actions;
|
|
599
698
|
return {
|
|
600
699
|
...release2,
|
|
601
|
-
|
|
700
|
+
actions: actionsForEntry
|
|
602
701
|
};
|
|
603
702
|
}
|
|
604
703
|
return release2;
|
|
@@ -657,28 +756,22 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
657
756
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
658
757
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
659
758
|
]);
|
|
660
|
-
const release2 = await strapi2.
|
|
759
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
661
760
|
if (!release2) {
|
|
662
761
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
663
762
|
}
|
|
664
763
|
if (release2.releasedAt) {
|
|
665
764
|
throw new errors.ValidationError("Release already published");
|
|
666
765
|
}
|
|
667
|
-
const updatedRelease = await strapi2.
|
|
668
|
-
|
|
669
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
670
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
671
|
-
*/
|
|
672
|
-
// @ts-expect-error see above
|
|
766
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
767
|
+
where: { id },
|
|
673
768
|
data: releaseWithCreatorFields
|
|
674
769
|
});
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
schedulingService.cancel(id);
|
|
681
|
-
}
|
|
770
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
771
|
+
if (releaseData.scheduledAt) {
|
|
772
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
773
|
+
} else if (release2.scheduledAt) {
|
|
774
|
+
schedulingService.cancel(id);
|
|
682
775
|
}
|
|
683
776
|
this.updateReleaseStatus(id);
|
|
684
777
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
@@ -692,7 +785,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
692
785
|
validateEntryContentType(action.entry.contentType),
|
|
693
786
|
validateUniqueEntry(releaseId, action)
|
|
694
787
|
]);
|
|
695
|
-
const release2 = await strapi2.
|
|
788
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
696
789
|
if (!release2) {
|
|
697
790
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
698
791
|
}
|
|
@@ -702,7 +795,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
702
795
|
const { entry, type } = action;
|
|
703
796
|
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
704
797
|
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
705
|
-
const releaseAction2 = await strapi2.
|
|
798
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
706
799
|
data: {
|
|
707
800
|
type,
|
|
708
801
|
contentType: entry.contentType,
|
|
@@ -715,32 +808,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
715
808
|
},
|
|
716
809
|
release: releaseId
|
|
717
810
|
},
|
|
718
|
-
populate: { release: {
|
|
811
|
+
populate: { release: { select: ["id"] }, entry: { select: ["id"] } }
|
|
719
812
|
});
|
|
720
813
|
this.updateReleaseStatus(releaseId);
|
|
721
814
|
return releaseAction2;
|
|
722
815
|
},
|
|
723
816
|
async findActions(releaseId, query) {
|
|
724
|
-
const release2 = await strapi2.
|
|
725
|
-
|
|
817
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
818
|
+
where: { id: releaseId },
|
|
819
|
+
select: ["id"]
|
|
726
820
|
});
|
|
727
821
|
if (!release2) {
|
|
728
822
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
729
823
|
}
|
|
730
|
-
|
|
731
|
-
|
|
824
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
825
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
826
|
+
...dbQuery,
|
|
732
827
|
populate: {
|
|
733
828
|
entry: {
|
|
734
829
|
populate: "*"
|
|
735
830
|
}
|
|
736
831
|
},
|
|
737
|
-
|
|
832
|
+
where: {
|
|
738
833
|
release: releaseId
|
|
739
834
|
}
|
|
740
835
|
});
|
|
741
836
|
},
|
|
742
837
|
async countActions(query) {
|
|
743
|
-
|
|
838
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
839
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
744
840
|
},
|
|
745
841
|
async groupActions(actions, groupBy) {
|
|
746
842
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -749,9 +845,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
749
845
|
}
|
|
750
846
|
return acc;
|
|
751
847
|
}, []);
|
|
752
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
753
|
-
contentTypeUids
|
|
754
|
-
);
|
|
848
|
+
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(contentTypeUids);
|
|
755
849
|
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
756
850
|
const formattedData = actions.map((action) => {
|
|
757
851
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
@@ -821,10 +915,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
821
915
|
return componentsMap;
|
|
822
916
|
},
|
|
823
917
|
async delete(releaseId) {
|
|
824
|
-
const release2 = await strapi2.
|
|
918
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
919
|
+
where: { id: releaseId },
|
|
825
920
|
populate: {
|
|
826
921
|
actions: {
|
|
827
|
-
|
|
922
|
+
select: ["id"]
|
|
828
923
|
}
|
|
829
924
|
}
|
|
830
925
|
});
|
|
@@ -842,9 +937,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
842
937
|
}
|
|
843
938
|
}
|
|
844
939
|
});
|
|
845
|
-
await strapi2.
|
|
940
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
941
|
+
where: {
|
|
942
|
+
id: releaseId
|
|
943
|
+
}
|
|
944
|
+
});
|
|
846
945
|
});
|
|
847
|
-
if (
|
|
946
|
+
if (release2.scheduledAt) {
|
|
848
947
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
849
948
|
await schedulingService.cancel(release2.id);
|
|
850
949
|
}
|
|
@@ -852,145 +951,69 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
852
951
|
return release2;
|
|
853
952
|
},
|
|
854
953
|
async publish(releaseId) {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
actions: {
|
|
862
|
-
populate: {
|
|
863
|
-
entry: {
|
|
864
|
-
fields: ["id"]
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
);
|
|
871
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
954
|
+
const {
|
|
955
|
+
release: release2,
|
|
956
|
+
error
|
|
957
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
958
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
959
|
+
if (!lockedRelease) {
|
|
872
960
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
873
961
|
}
|
|
874
|
-
if (
|
|
962
|
+
if (lockedRelease.releasedAt) {
|
|
875
963
|
throw new errors.ValidationError("Release already published");
|
|
876
964
|
}
|
|
877
|
-
if (
|
|
878
|
-
throw new errors.ValidationError("
|
|
965
|
+
if (lockedRelease.status === "failed") {
|
|
966
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
879
967
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
collectionTypeActions[contentTypeUid] = {
|
|
887
|
-
entriestoPublishIds: [],
|
|
888
|
-
entriesToUnpublishIds: []
|
|
889
|
-
};
|
|
890
|
-
}
|
|
891
|
-
if (action.type === "publish") {
|
|
892
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
893
|
-
} else {
|
|
894
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
895
|
-
}
|
|
896
|
-
} else {
|
|
897
|
-
singleTypeActions.push({
|
|
898
|
-
uid: contentTypeUid,
|
|
899
|
-
action: action.type,
|
|
900
|
-
id: action.entry.id
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
905
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
906
|
-
await strapi2.db.transaction(async () => {
|
|
907
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
908
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
909
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
910
|
-
try {
|
|
911
|
-
if (action === "publish") {
|
|
912
|
-
await entityManagerService.publish(entry, uid);
|
|
913
|
-
} else {
|
|
914
|
-
await entityManagerService.unpublish(entry, uid);
|
|
915
|
-
}
|
|
916
|
-
} catch (error) {
|
|
917
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
918
|
-
} else {
|
|
919
|
-
throw error;
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
924
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
925
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
926
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
927
|
-
contentTypeUid,
|
|
928
|
-
{
|
|
929
|
-
filters: {
|
|
930
|
-
id: {
|
|
931
|
-
$in: entriestoPublishIds
|
|
932
|
-
}
|
|
933
|
-
},
|
|
934
|
-
populate
|
|
935
|
-
}
|
|
936
|
-
);
|
|
937
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
938
|
-
contentTypeUid,
|
|
939
|
-
{
|
|
940
|
-
filters: {
|
|
941
|
-
id: {
|
|
942
|
-
$in: entriesToUnpublishIds
|
|
943
|
-
}
|
|
944
|
-
},
|
|
945
|
-
populate
|
|
946
|
-
}
|
|
947
|
-
);
|
|
948
|
-
if (entriesToPublish.length > 0) {
|
|
949
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
968
|
+
try {
|
|
969
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
970
|
+
const { collectionTypeActions, singleTypeActions } = await getFormattedActions(releaseId);
|
|
971
|
+
await strapi2.db.transaction(async () => {
|
|
972
|
+
for (const { uid, action, id } of singleTypeActions) {
|
|
973
|
+
await publishSingleTypeAction(uid, action, id);
|
|
950
974
|
}
|
|
951
|
-
|
|
952
|
-
|
|
975
|
+
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
976
|
+
const uid = contentTypeUid;
|
|
977
|
+
await publishCollectionTypeAction(
|
|
978
|
+
uid,
|
|
979
|
+
collectionTypeActions[uid].entriesToPublishIds,
|
|
980
|
+
collectionTypeActions[uid].entriesToUnpublishIds
|
|
981
|
+
);
|
|
953
982
|
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
963
|
-
},
|
|
964
|
-
populate: {
|
|
965
|
-
actions: {
|
|
966
|
-
// @ts-expect-error is not expecting count but it is working
|
|
967
|
-
count: true
|
|
983
|
+
});
|
|
984
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
985
|
+
where: {
|
|
986
|
+
id: releaseId
|
|
987
|
+
},
|
|
988
|
+
data: {
|
|
989
|
+
status: "done",
|
|
990
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
968
991
|
}
|
|
969
|
-
}
|
|
970
|
-
});
|
|
971
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
992
|
+
});
|
|
972
993
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
973
994
|
isPublished: true,
|
|
974
|
-
release:
|
|
995
|
+
release: release22
|
|
975
996
|
});
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
} catch (error) {
|
|
980
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
997
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
998
|
+
return { release: release22, error: null };
|
|
999
|
+
} catch (error2) {
|
|
981
1000
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
982
1001
|
isPublished: false,
|
|
983
|
-
error
|
|
1002
|
+
error: error2
|
|
984
1003
|
});
|
|
985
|
-
|
|
986
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
987
|
-
where: { id: releaseId },
|
|
988
|
-
data: {
|
|
1004
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
989
1005
|
status: "failed"
|
|
990
|
-
}
|
|
991
|
-
|
|
1006
|
+
}).transacting(trx).execute();
|
|
1007
|
+
return {
|
|
1008
|
+
release: null,
|
|
1009
|
+
error: error2
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
if (error instanceof Error) {
|
|
992
1014
|
throw error;
|
|
993
1015
|
}
|
|
1016
|
+
return release2;
|
|
994
1017
|
},
|
|
995
1018
|
async updateAction(actionId, releaseId, update) {
|
|
996
1019
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -1077,10 +1100,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1077
1100
|
}
|
|
1078
1101
|
};
|
|
1079
1102
|
};
|
|
1103
|
+
class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
1104
|
+
constructor(message) {
|
|
1105
|
+
super(message);
|
|
1106
|
+
this.name = "AlreadyOnReleaseError";
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1080
1109
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1081
1110
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1082
|
-
const release2 = await strapi2.
|
|
1083
|
-
|
|
1111
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1112
|
+
where: {
|
|
1113
|
+
id: releaseId
|
|
1114
|
+
},
|
|
1115
|
+
populate: { actions: { populate: { entry: { select: ["id"] } } } }
|
|
1084
1116
|
});
|
|
1085
1117
|
if (!release2) {
|
|
1086
1118
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -1089,7 +1121,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1089
1121
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1090
1122
|
);
|
|
1091
1123
|
if (isEntryInRelease) {
|
|
1092
|
-
throw new
|
|
1124
|
+
throw new AlreadyOnReleaseError(
|
|
1093
1125
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1094
1126
|
);
|
|
1095
1127
|
}
|
|
@@ -1106,10 +1138,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1106
1138
|
}
|
|
1107
1139
|
},
|
|
1108
1140
|
async validatePendingReleasesLimit() {
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1111
|
-
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1112
|
-
);
|
|
1141
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1142
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1113
1143
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1114
1144
|
filters: {
|
|
1115
1145
|
releasedAt: {
|
|
@@ -1122,8 +1152,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1122
1152
|
}
|
|
1123
1153
|
},
|
|
1124
1154
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1125
|
-
const pendingReleases = await strapi2.
|
|
1126
|
-
|
|
1155
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1156
|
+
where: {
|
|
1127
1157
|
releasedAt: {
|
|
1128
1158
|
$null: true
|
|
1129
1159
|
},
|
|
@@ -1152,7 +1182,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1152
1182
|
}
|
|
1153
1183
|
const job = scheduleJob(scheduleDate, async () => {
|
|
1154
1184
|
try {
|
|
1155
|
-
await getService("release").publish(releaseId);
|
|
1185
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1156
1186
|
} catch (error) {
|
|
1157
1187
|
}
|
|
1158
1188
|
this.cancel(releaseId);
|
|
@@ -1197,7 +1227,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1197
1227
|
const services = {
|
|
1198
1228
|
release: createReleaseService,
|
|
1199
1229
|
"release-validation": createReleaseValidationService,
|
|
1200
|
-
|
|
1230
|
+
scheduling: createSchedulingService
|
|
1201
1231
|
};
|
|
1202
1232
|
const RELEASE_SCHEMA = yup.object().shape({
|
|
1203
1233
|
name: yup.string().trim().required(),
|
|
@@ -1222,7 +1252,7 @@ const RELEASE_SCHEMA = yup.object().shape({
|
|
|
1222
1252
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
1223
1253
|
const releaseController = {
|
|
1224
1254
|
async findMany(ctx) {
|
|
1225
|
-
const permissionsManager = strapi.admin
|
|
1255
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1226
1256
|
ability: ctx.state.userAbility,
|
|
1227
1257
|
model: RELEASE_MODEL_UID
|
|
1228
1258
|
});
|
|
@@ -1250,7 +1280,7 @@ const releaseController = {
|
|
|
1250
1280
|
}
|
|
1251
1281
|
};
|
|
1252
1282
|
});
|
|
1253
|
-
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1283
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1254
1284
|
where: {
|
|
1255
1285
|
releasedAt: null
|
|
1256
1286
|
}
|
|
@@ -1272,7 +1302,7 @@ const releaseController = {
|
|
|
1272
1302
|
});
|
|
1273
1303
|
const sanitizedRelease = {
|
|
1274
1304
|
...release2,
|
|
1275
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1305
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1276
1306
|
};
|
|
1277
1307
|
const data = {
|
|
1278
1308
|
...sanitizedRelease,
|
|
@@ -1284,19 +1314,48 @@ const releaseController = {
|
|
|
1284
1314
|
};
|
|
1285
1315
|
ctx.body = { data };
|
|
1286
1316
|
},
|
|
1317
|
+
async mapEntriesToReleases(ctx) {
|
|
1318
|
+
const { contentTypeUid, entriesIds } = ctx.query;
|
|
1319
|
+
if (!contentTypeUid || !entriesIds) {
|
|
1320
|
+
throw new errors.ValidationError("Missing required query parameters");
|
|
1321
|
+
}
|
|
1322
|
+
const releaseService = getService("release", { strapi });
|
|
1323
|
+
const releasesWithActions = await releaseService.findManyWithContentTypeEntryAttached(
|
|
1324
|
+
contentTypeUid,
|
|
1325
|
+
entriesIds
|
|
1326
|
+
);
|
|
1327
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1328
|
+
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1329
|
+
(acc, release2) => {
|
|
1330
|
+
release2.actions.forEach((action) => {
|
|
1331
|
+
if (!acc[action.entry.id]) {
|
|
1332
|
+
acc[action.entry.id] = [{ id: release2.id, name: release2.name }];
|
|
1333
|
+
} else {
|
|
1334
|
+
acc[action.entry.id].push({ id: release2.id, name: release2.name });
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
return acc;
|
|
1338
|
+
},
|
|
1339
|
+
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1340
|
+
{}
|
|
1341
|
+
);
|
|
1342
|
+
ctx.body = {
|
|
1343
|
+
data: mappedEntriesInReleases
|
|
1344
|
+
};
|
|
1345
|
+
},
|
|
1287
1346
|
async create(ctx) {
|
|
1288
1347
|
const user = ctx.state.user;
|
|
1289
1348
|
const releaseArgs = ctx.request.body;
|
|
1290
1349
|
await validateRelease(releaseArgs);
|
|
1291
1350
|
const releaseService = getService("release", { strapi });
|
|
1292
1351
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1293
|
-
const permissionsManager = strapi.admin
|
|
1352
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1294
1353
|
ability: ctx.state.userAbility,
|
|
1295
1354
|
model: RELEASE_MODEL_UID
|
|
1296
1355
|
});
|
|
1297
|
-
ctx.
|
|
1356
|
+
ctx.created({
|
|
1298
1357
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1299
|
-
};
|
|
1358
|
+
});
|
|
1300
1359
|
},
|
|
1301
1360
|
async update(ctx) {
|
|
1302
1361
|
const user = ctx.state.user;
|
|
@@ -1305,7 +1364,7 @@ const releaseController = {
|
|
|
1305
1364
|
await validateRelease(releaseArgs);
|
|
1306
1365
|
const releaseService = getService("release", { strapi });
|
|
1307
1366
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1308
|
-
const permissionsManager = strapi.admin
|
|
1367
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1309
1368
|
ability: ctx.state.userAbility,
|
|
1310
1369
|
model: RELEASE_MODEL_UID
|
|
1311
1370
|
});
|
|
@@ -1369,13 +1428,45 @@ const releaseActionController = {
|
|
|
1369
1428
|
await validateReleaseAction(releaseActionArgs);
|
|
1370
1429
|
const releaseService = getService("release", { strapi });
|
|
1371
1430
|
const releaseAction2 = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1372
|
-
ctx.
|
|
1431
|
+
ctx.created({
|
|
1373
1432
|
data: releaseAction2
|
|
1374
|
-
};
|
|
1433
|
+
});
|
|
1434
|
+
},
|
|
1435
|
+
async createMany(ctx) {
|
|
1436
|
+
const releaseId = ctx.params.releaseId;
|
|
1437
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1438
|
+
await Promise.all(
|
|
1439
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1440
|
+
);
|
|
1441
|
+
const releaseService = getService("release", { strapi });
|
|
1442
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1443
|
+
const releaseActions2 = await Promise.all(
|
|
1444
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1445
|
+
try {
|
|
1446
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1447
|
+
return action;
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1450
|
+
return null;
|
|
1451
|
+
}
|
|
1452
|
+
throw error;
|
|
1453
|
+
}
|
|
1454
|
+
})
|
|
1455
|
+
);
|
|
1456
|
+
return releaseActions2;
|
|
1457
|
+
});
|
|
1458
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1459
|
+
ctx.created({
|
|
1460
|
+
data: newReleaseActions,
|
|
1461
|
+
meta: {
|
|
1462
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1463
|
+
totalEntries: releaseActions.length
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1375
1466
|
},
|
|
1376
1467
|
async findMany(ctx) {
|
|
1377
1468
|
const releaseId = ctx.params.releaseId;
|
|
1378
|
-
const permissionsManager = strapi.admin
|
|
1469
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1379
1470
|
ability: ctx.state.userAbility,
|
|
1380
1471
|
model: RELEASE_ACTION_MODEL_UID
|
|
1381
1472
|
});
|
|
@@ -1389,14 +1480,14 @@ const releaseActionController = {
|
|
|
1389
1480
|
if (acc[action.contentType]) {
|
|
1390
1481
|
return acc;
|
|
1391
1482
|
}
|
|
1392
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1483
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1393
1484
|
ability: ctx.state.userAbility,
|
|
1394
1485
|
model: action.contentType
|
|
1395
1486
|
});
|
|
1396
1487
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1397
1488
|
return acc;
|
|
1398
1489
|
}, {});
|
|
1399
|
-
const sanitizedResults = await
|
|
1490
|
+
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1400
1491
|
...action,
|
|
1401
1492
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1402
1493
|
}));
|
|
@@ -1441,6 +1532,22 @@ const controllers = { release: releaseController, "release-action": releaseActio
|
|
|
1441
1532
|
const release = {
|
|
1442
1533
|
type: "admin",
|
|
1443
1534
|
routes: [
|
|
1535
|
+
{
|
|
1536
|
+
method: "GET",
|
|
1537
|
+
path: "/mapEntriesToReleases",
|
|
1538
|
+
handler: "release.mapEntriesToReleases",
|
|
1539
|
+
config: {
|
|
1540
|
+
policies: [
|
|
1541
|
+
"admin::isAuthenticatedAdmin",
|
|
1542
|
+
{
|
|
1543
|
+
name: "admin::hasPermissions",
|
|
1544
|
+
config: {
|
|
1545
|
+
actions: ["plugin::content-releases.read"]
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
]
|
|
1549
|
+
}
|
|
1550
|
+
},
|
|
1444
1551
|
{
|
|
1445
1552
|
method: "POST",
|
|
1446
1553
|
path: "/",
|
|
@@ -1558,6 +1665,22 @@ const releaseAction = {
|
|
|
1558
1665
|
]
|
|
1559
1666
|
}
|
|
1560
1667
|
},
|
|
1668
|
+
{
|
|
1669
|
+
method: "POST",
|
|
1670
|
+
path: "/:releaseId/actions/bulk",
|
|
1671
|
+
handler: "release-action.createMany",
|
|
1672
|
+
config: {
|
|
1673
|
+
policies: [
|
|
1674
|
+
"admin::isAuthenticatedAdmin",
|
|
1675
|
+
{
|
|
1676
|
+
name: "admin::hasPermissions",
|
|
1677
|
+
config: {
|
|
1678
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
]
|
|
1682
|
+
}
|
|
1683
|
+
},
|
|
1561
1684
|
{
|
|
1562
1685
|
method: "GET",
|
|
1563
1686
|
path: "/:releaseId/actions",
|
|
@@ -1612,9 +1735,8 @@ const routes = {
|
|
|
1612
1735
|
release,
|
|
1613
1736
|
"release-action": releaseAction
|
|
1614
1737
|
};
|
|
1615
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1616
1738
|
const getPlugin = () => {
|
|
1617
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1739
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1618
1740
|
return {
|
|
1619
1741
|
register,
|
|
1620
1742
|
bootstrap,
|