@strapi/content-releases 0.0.0-experimental.d4cb32ce579e12a4436d68036f2327132fba1309 → 0.0.0-experimental.d53e940834bf72ddc725f1d2fd36dac9abec30cb
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-xAkiD42p.mjs → App-B2R2exNT.mjs} +656 -625
- package/dist/_chunks/App-B2R2exNT.mjs.map +1 -0
- package/dist/_chunks/{App-OK4Xac-O.js → App-CEwOQkKT.js} +671 -641
- package/dist/_chunks/App-CEwOQkKT.js.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-veqvqeEr.mjs → en-B9Ur3VsE.mjs} +14 -5
- package/dist/_chunks/en-B9Ur3VsE.mjs.map +1 -0
- package/dist/_chunks/{en-r0otWaln.js → en-DtFJ5ViE.js} +14 -5
- package/dist/_chunks/en-DtFJ5ViE.js.map +1 -0
- package/dist/_chunks/{index-JvA2_26n.js → index-BrWv-zV4.js} +258 -244
- package/dist/_chunks/index-BrWv-zV4.js.map +1 -0
- package/dist/_chunks/{index-exoiSU3V.mjs → index-DbmynICx.mjs} +264 -248
- package/dist/_chunks/index-DbmynICx.mjs.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 +675 -232
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +675 -232
- 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-OK4Xac-O.js.map +0 -1
- package/dist/_chunks/App-xAkiD42p.mjs.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-r0otWaln.js.map +0 -1
- package/dist/_chunks/en-veqvqeEr.mjs.map +0 -1
- package/dist/_chunks/index-JvA2_26n.js.map +0 -1
- package/dist/_chunks/index-exoiSU3V.mjs.map +0 -1
package/dist/server/index.mjs
CHANGED
|
@@ -1,7 +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
|
+
import isEqual from "lodash/isEqual";
|
|
2
3
|
import { difference, keys } from "lodash";
|
|
3
4
|
import _ from "lodash/fp";
|
|
4
|
-
import EE from "@strapi/strapi/dist/utils/ee";
|
|
5
5
|
import { scheduleJob } from "node-schedule";
|
|
6
6
|
import * as yup from "yup";
|
|
7
7
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
@@ -53,6 +53,32 @@ const ACTIONS = [
|
|
|
53
53
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
54
54
|
RELEASES_PUBLISH: "releases.publish"
|
|
55
55
|
};
|
|
56
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
57
|
+
return strapi2.plugin("content-releases").service(name);
|
|
58
|
+
};
|
|
59
|
+
const getPopulatedEntry = async (contentTypeUid, entryId, { strapi: strapi2 }) => {
|
|
60
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
61
|
+
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
62
|
+
const entry = await strapi2.db.query(contentTypeUid).findOne({
|
|
63
|
+
where: { id: entryId },
|
|
64
|
+
populate
|
|
65
|
+
});
|
|
66
|
+
return entry;
|
|
67
|
+
};
|
|
68
|
+
const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
69
|
+
try {
|
|
70
|
+
await strapi2.entityValidator.validateEntityCreation(
|
|
71
|
+
strapi2.getModel(contentTypeUid),
|
|
72
|
+
entry,
|
|
73
|
+
void 0,
|
|
74
|
+
// @ts-expect-error - FIXME: entity here is unnecessary
|
|
75
|
+
entry
|
|
76
|
+
);
|
|
77
|
+
return true;
|
|
78
|
+
} catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
56
82
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
57
83
|
oldContentTypes,
|
|
58
84
|
contentTypes: contentTypes2
|
|
@@ -74,36 +100,205 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
74
100
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
75
101
|
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes2)) ?? [];
|
|
76
102
|
if (deletedContentTypes.length) {
|
|
77
|
-
await
|
|
103
|
+
await async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
78
104
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
79
105
|
});
|
|
80
106
|
}
|
|
81
107
|
}
|
|
82
|
-
|
|
108
|
+
async function migrateIsValidAndStatusReleases() {
|
|
109
|
+
const releasesWithoutStatus = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
110
|
+
where: {
|
|
111
|
+
status: null,
|
|
112
|
+
releasedAt: null
|
|
113
|
+
},
|
|
114
|
+
populate: {
|
|
115
|
+
actions: {
|
|
116
|
+
populate: {
|
|
117
|
+
entry: true
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
async.map(releasesWithoutStatus, async (release2) => {
|
|
123
|
+
const actions = release2.actions;
|
|
124
|
+
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
125
|
+
for (const action of notValidatedActions) {
|
|
126
|
+
if (action.entry) {
|
|
127
|
+
const populatedEntry = await getPopulatedEntry(action.contentType, action.entry.id, {
|
|
128
|
+
strapi
|
|
129
|
+
});
|
|
130
|
+
if (populatedEntry) {
|
|
131
|
+
const isEntryValid = getEntryValidStatus(action.contentType, populatedEntry, { strapi });
|
|
132
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
133
|
+
where: {
|
|
134
|
+
id: action.id
|
|
135
|
+
},
|
|
136
|
+
data: {
|
|
137
|
+
isEntryValid
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
144
|
+
});
|
|
145
|
+
const publishedReleases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
146
|
+
where: {
|
|
147
|
+
status: null,
|
|
148
|
+
releasedAt: {
|
|
149
|
+
$notNull: true
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
async.map(publishedReleases, async (release2) => {
|
|
154
|
+
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
155
|
+
where: {
|
|
156
|
+
id: release2.id
|
|
157
|
+
},
|
|
158
|
+
data: {
|
|
159
|
+
status: "done"
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
165
|
+
if (oldContentTypes !== void 0 && contentTypes2 !== void 0) {
|
|
166
|
+
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes).filter(
|
|
167
|
+
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
168
|
+
);
|
|
169
|
+
const releasesAffected = /* @__PURE__ */ new Set();
|
|
170
|
+
async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
171
|
+
const oldContentType = oldContentTypes[contentTypeUID];
|
|
172
|
+
const contentType = contentTypes2[contentTypeUID];
|
|
173
|
+
if (!isEqual(oldContentType?.attributes, contentType?.attributes)) {
|
|
174
|
+
const actions = await strapi.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
175
|
+
where: {
|
|
176
|
+
contentType: contentTypeUID
|
|
177
|
+
},
|
|
178
|
+
populate: {
|
|
179
|
+
entry: true,
|
|
180
|
+
release: true
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
await async.map(actions, async (action) => {
|
|
184
|
+
if (action.entry && action.release) {
|
|
185
|
+
const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
|
|
186
|
+
strapi
|
|
187
|
+
});
|
|
188
|
+
if (populatedEntry) {
|
|
189
|
+
const isEntryValid = await getEntryValidStatus(contentTypeUID, populatedEntry, {
|
|
190
|
+
strapi
|
|
191
|
+
});
|
|
192
|
+
releasesAffected.add(action.release.id);
|
|
193
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
194
|
+
where: {
|
|
195
|
+
id: action.id
|
|
196
|
+
},
|
|
197
|
+
data: {
|
|
198
|
+
isEntryValid
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}).then(() => {
|
|
206
|
+
async.map(releasesAffected, async (releaseId) => {
|
|
207
|
+
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
213
|
+
if (!oldContentTypes) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
217
|
+
if (!i18nPlugin) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
for (const uid in contentTypes2) {
|
|
221
|
+
if (!oldContentTypes[uid]) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const oldContentType = oldContentTypes[uid];
|
|
225
|
+
const contentType = contentTypes2[uid];
|
|
226
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
227
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
228
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
229
|
+
locale: null
|
|
230
|
+
}).where({ contentType: uid }).execute();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
235
|
+
if (!oldContentTypes) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
239
|
+
if (!i18nPlugin) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
for (const uid in contentTypes2) {
|
|
243
|
+
if (!oldContentTypes[uid]) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const oldContentType = oldContentTypes[uid];
|
|
247
|
+
const contentType = contentTypes2[uid];
|
|
248
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
249
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
250
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
251
|
+
const defaultLocale = await getDefaultLocale();
|
|
252
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
253
|
+
locale: defaultLocale
|
|
254
|
+
}).where({ contentType: uid }).execute();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
83
258
|
const register = async ({ strapi: strapi2 }) => {
|
|
84
|
-
if (features
|
|
85
|
-
await strapi2.admin
|
|
86
|
-
strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish);
|
|
87
|
-
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType);
|
|
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);
|
|
262
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
263
|
+
}
|
|
264
|
+
if (strapi2.plugin("graphql")) {
|
|
265
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
266
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
267
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
88
268
|
}
|
|
89
269
|
};
|
|
90
|
-
const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
91
|
-
return strapi2.plugin("content-releases").service(name);
|
|
92
|
-
};
|
|
93
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
94
270
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
95
|
-
if (features
|
|
271
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
272
|
+
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
273
|
+
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
274
|
+
);
|
|
96
275
|
strapi2.db.lifecycles.subscribe({
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
276
|
+
models: contentTypesWithDraftAndPublish,
|
|
277
|
+
async afterDelete(event) {
|
|
278
|
+
try {
|
|
279
|
+
const { model, result } = event;
|
|
280
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
281
|
+
const { id } = result;
|
|
282
|
+
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
283
|
+
where: {
|
|
284
|
+
actions: {
|
|
285
|
+
target_type: model.uid,
|
|
286
|
+
target_id: id
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
291
|
+
where: {
|
|
292
|
+
target_type: model.uid,
|
|
293
|
+
target_id: id
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
for (const release2 of releases) {
|
|
297
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
105
298
|
}
|
|
106
|
-
}
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
107
302
|
}
|
|
108
303
|
},
|
|
109
304
|
/**
|
|
@@ -123,41 +318,88 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
123
318
|
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
124
319
|
*/
|
|
125
320
|
async afterDeleteMany(event) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
321
|
+
try {
|
|
322
|
+
const { model, state } = event;
|
|
323
|
+
const entriesToDelete = state.entriesToDelete;
|
|
324
|
+
if (entriesToDelete) {
|
|
325
|
+
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
326
|
+
where: {
|
|
327
|
+
actions: {
|
|
328
|
+
target_type: model.uid,
|
|
329
|
+
target_id: {
|
|
330
|
+
$in: entriesToDelete.map((entry) => entry.id)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
134
333
|
}
|
|
334
|
+
});
|
|
335
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
336
|
+
where: {
|
|
337
|
+
target_type: model.uid,
|
|
338
|
+
target_id: {
|
|
339
|
+
$in: entriesToDelete.map((entry) => entry.id)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
for (const release2 of releases) {
|
|
344
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
135
345
|
}
|
|
346
|
+
}
|
|
347
|
+
} catch (error) {
|
|
348
|
+
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
349
|
+
error
|
|
136
350
|
});
|
|
137
351
|
}
|
|
352
|
+
},
|
|
353
|
+
async afterUpdate(event) {
|
|
354
|
+
try {
|
|
355
|
+
const { model, result } = event;
|
|
356
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
357
|
+
const isEntryValid = await getEntryValidStatus(model.uid, result, {
|
|
358
|
+
strapi: strapi2
|
|
359
|
+
});
|
|
360
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
361
|
+
where: {
|
|
362
|
+
target_type: model.uid,
|
|
363
|
+
target_id: result.id
|
|
364
|
+
},
|
|
365
|
+
data: {
|
|
366
|
+
isEntryValid
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
370
|
+
where: {
|
|
371
|
+
actions: {
|
|
372
|
+
target_type: model.uid,
|
|
373
|
+
target_id: result.id
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
for (const release2 of releases) {
|
|
378
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
383
|
+
}
|
|
138
384
|
}
|
|
139
385
|
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
}
|
|
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
|
+
});
|
|
151
395
|
}
|
|
152
396
|
};
|
|
153
397
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
job.cancel();
|
|
160
|
-
}
|
|
398
|
+
const scheduledJobs = getService("scheduling", {
|
|
399
|
+
strapi: strapi2
|
|
400
|
+
}).getAll();
|
|
401
|
+
for (const [, job] of scheduledJobs) {
|
|
402
|
+
job.cancel();
|
|
161
403
|
}
|
|
162
404
|
};
|
|
163
405
|
const schema$1 = {
|
|
@@ -192,6 +434,11 @@ const schema$1 = {
|
|
|
192
434
|
timezone: {
|
|
193
435
|
type: "string"
|
|
194
436
|
},
|
|
437
|
+
status: {
|
|
438
|
+
type: "enumeration",
|
|
439
|
+
enum: ["ready", "blocked", "failed", "done", "empty"],
|
|
440
|
+
required: true
|
|
441
|
+
},
|
|
195
442
|
actions: {
|
|
196
443
|
type: "relation",
|
|
197
444
|
relation: "oneToMany",
|
|
@@ -244,6 +491,9 @@ const schema = {
|
|
|
244
491
|
relation: "manyToOne",
|
|
245
492
|
target: RELEASE_MODEL_UID,
|
|
246
493
|
inversedBy: "actions"
|
|
494
|
+
},
|
|
495
|
+
isEntryValid: {
|
|
496
|
+
type: "boolean"
|
|
247
497
|
}
|
|
248
498
|
}
|
|
249
499
|
};
|
|
@@ -274,6 +524,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
274
524
|
release: release2
|
|
275
525
|
});
|
|
276
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
|
+
};
|
|
277
615
|
return {
|
|
278
616
|
async create(releaseData, { user }) {
|
|
279
617
|
const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
|
|
@@ -287,10 +625,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
287
625
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
288
626
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
289
627
|
]);
|
|
290
|
-
const release2 = await strapi2.
|
|
291
|
-
data:
|
|
628
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
629
|
+
data: {
|
|
630
|
+
...releaseWithCreatorFields,
|
|
631
|
+
status: "empty"
|
|
632
|
+
}
|
|
292
633
|
});
|
|
293
|
-
if (
|
|
634
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
294
635
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
295
636
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
296
637
|
}
|
|
@@ -298,28 +639,36 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
298
639
|
return release2;
|
|
299
640
|
},
|
|
300
641
|
async findOne(id, query = {}) {
|
|
301
|
-
const
|
|
302
|
-
|
|
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 }
|
|
303
646
|
});
|
|
304
647
|
return release2;
|
|
305
648
|
},
|
|
306
649
|
findPage(query) {
|
|
307
|
-
|
|
308
|
-
|
|
650
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
651
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
652
|
+
...dbQuery,
|
|
309
653
|
populate: {
|
|
310
654
|
actions: {
|
|
311
|
-
// @ts-expect-error Ignore missing properties
|
|
312
655
|
count: true
|
|
313
656
|
}
|
|
314
657
|
}
|
|
315
658
|
});
|
|
316
659
|
},
|
|
317
|
-
async findManyWithContentTypeEntryAttached(contentTypeUid,
|
|
660
|
+
async findManyWithContentTypeEntryAttached(contentTypeUid, entriesIds) {
|
|
661
|
+
let entries = entriesIds;
|
|
662
|
+
if (!Array.isArray(entriesIds)) {
|
|
663
|
+
entries = [entriesIds];
|
|
664
|
+
}
|
|
318
665
|
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
319
666
|
where: {
|
|
320
667
|
actions: {
|
|
321
668
|
target_type: contentTypeUid,
|
|
322
|
-
target_id:
|
|
669
|
+
target_id: {
|
|
670
|
+
$in: entries
|
|
671
|
+
}
|
|
323
672
|
},
|
|
324
673
|
releasedAt: {
|
|
325
674
|
$null: true
|
|
@@ -330,18 +679,25 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
330
679
|
actions: {
|
|
331
680
|
where: {
|
|
332
681
|
target_type: contentTypeUid,
|
|
333
|
-
target_id:
|
|
682
|
+
target_id: {
|
|
683
|
+
$in: entries
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
populate: {
|
|
687
|
+
entry: {
|
|
688
|
+
select: ["id"]
|
|
689
|
+
}
|
|
334
690
|
}
|
|
335
691
|
}
|
|
336
692
|
}
|
|
337
693
|
});
|
|
338
694
|
return releases.map((release2) => {
|
|
339
695
|
if (release2.actions?.length) {
|
|
340
|
-
const
|
|
696
|
+
const actionsForEntry = release2.actions;
|
|
341
697
|
delete release2.actions;
|
|
342
698
|
return {
|
|
343
699
|
...release2,
|
|
344
|
-
|
|
700
|
+
actions: actionsForEntry
|
|
345
701
|
};
|
|
346
702
|
}
|
|
347
703
|
return release2;
|
|
@@ -400,29 +756,24 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
400
756
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
401
757
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
402
758
|
]);
|
|
403
|
-
const release2 = await strapi2.
|
|
759
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
404
760
|
if (!release2) {
|
|
405
761
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
406
762
|
}
|
|
407
763
|
if (release2.releasedAt) {
|
|
408
764
|
throw new errors.ValidationError("Release already published");
|
|
409
765
|
}
|
|
410
|
-
const updatedRelease = await strapi2.
|
|
411
|
-
|
|
412
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
413
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
414
|
-
*/
|
|
415
|
-
// @ts-expect-error see above
|
|
766
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
767
|
+
where: { id },
|
|
416
768
|
data: releaseWithCreatorFields
|
|
417
769
|
});
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
schedulingService.cancel(id);
|
|
424
|
-
}
|
|
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);
|
|
425
775
|
}
|
|
776
|
+
this.updateReleaseStatus(id);
|
|
426
777
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
427
778
|
return updatedRelease;
|
|
428
779
|
},
|
|
@@ -434,7 +785,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
434
785
|
validateEntryContentType(action.entry.contentType),
|
|
435
786
|
validateUniqueEntry(releaseId, action)
|
|
436
787
|
]);
|
|
437
|
-
const release2 = await strapi2.
|
|
788
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
438
789
|
if (!release2) {
|
|
439
790
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
440
791
|
}
|
|
@@ -442,11 +793,14 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
442
793
|
throw new errors.ValidationError("Release already published");
|
|
443
794
|
}
|
|
444
795
|
const { entry, type } = action;
|
|
445
|
-
|
|
796
|
+
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
797
|
+
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
798
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
446
799
|
data: {
|
|
447
800
|
type,
|
|
448
801
|
contentType: entry.contentType,
|
|
449
802
|
locale: entry.locale,
|
|
803
|
+
isEntryValid,
|
|
450
804
|
entry: {
|
|
451
805
|
id: entry.id,
|
|
452
806
|
__type: entry.contentType,
|
|
@@ -454,30 +808,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
454
808
|
},
|
|
455
809
|
release: releaseId
|
|
456
810
|
},
|
|
457
|
-
populate: { release: {
|
|
811
|
+
populate: { release: { select: ["id"] }, entry: { select: ["id"] } }
|
|
458
812
|
});
|
|
813
|
+
this.updateReleaseStatus(releaseId);
|
|
814
|
+
return releaseAction2;
|
|
459
815
|
},
|
|
460
816
|
async findActions(releaseId, query) {
|
|
461
|
-
const release2 = await strapi2.
|
|
462
|
-
|
|
817
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
818
|
+
where: { id: releaseId },
|
|
819
|
+
select: ["id"]
|
|
463
820
|
});
|
|
464
821
|
if (!release2) {
|
|
465
822
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
466
823
|
}
|
|
467
|
-
|
|
468
|
-
|
|
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,
|
|
469
827
|
populate: {
|
|
470
828
|
entry: {
|
|
471
829
|
populate: "*"
|
|
472
830
|
}
|
|
473
831
|
},
|
|
474
|
-
|
|
832
|
+
where: {
|
|
475
833
|
release: releaseId
|
|
476
834
|
}
|
|
477
835
|
});
|
|
478
836
|
},
|
|
479
837
|
async countActions(query) {
|
|
480
|
-
|
|
838
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
839
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
481
840
|
},
|
|
482
841
|
async groupActions(actions, groupBy) {
|
|
483
842
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -486,9 +845,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
486
845
|
}
|
|
487
846
|
return acc;
|
|
488
847
|
}, []);
|
|
489
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
490
|
-
contentTypeUids
|
|
491
|
-
);
|
|
848
|
+
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(contentTypeUids);
|
|
492
849
|
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
493
850
|
const formattedData = actions.map((action) => {
|
|
494
851
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
@@ -558,10 +915,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
558
915
|
return componentsMap;
|
|
559
916
|
},
|
|
560
917
|
async delete(releaseId) {
|
|
561
|
-
const release2 = await strapi2.
|
|
918
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
919
|
+
where: { id: releaseId },
|
|
562
920
|
populate: {
|
|
563
921
|
actions: {
|
|
564
|
-
|
|
922
|
+
select: ["id"]
|
|
565
923
|
}
|
|
566
924
|
}
|
|
567
925
|
});
|
|
@@ -579,9 +937,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
579
937
|
}
|
|
580
938
|
}
|
|
581
939
|
});
|
|
582
|
-
await strapi2.
|
|
940
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
941
|
+
where: {
|
|
942
|
+
id: releaseId
|
|
943
|
+
}
|
|
944
|
+
});
|
|
583
945
|
});
|
|
584
|
-
if (
|
|
946
|
+
if (release2.scheduledAt) {
|
|
585
947
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
586
948
|
await schedulingService.cancel(release2.id);
|
|
587
949
|
}
|
|
@@ -589,139 +951,69 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
589
951
|
return release2;
|
|
590
952
|
},
|
|
591
953
|
async publish(releaseId) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
actions: {
|
|
599
|
-
populate: {
|
|
600
|
-
entry: {
|
|
601
|
-
fields: ["id"]
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
);
|
|
608
|
-
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) {
|
|
609
960
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
610
961
|
}
|
|
611
|
-
if (
|
|
962
|
+
if (lockedRelease.releasedAt) {
|
|
612
963
|
throw new errors.ValidationError("Release already published");
|
|
613
964
|
}
|
|
614
|
-
if (
|
|
615
|
-
throw new errors.ValidationError("
|
|
965
|
+
if (lockedRelease.status === "failed") {
|
|
966
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
616
967
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
collectionTypeActions[contentTypeUid] = {
|
|
624
|
-
entriestoPublishIds: [],
|
|
625
|
-
entriesToUnpublishIds: []
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
if (action.type === "publish") {
|
|
629
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
630
|
-
} else {
|
|
631
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
632
|
-
}
|
|
633
|
-
} else {
|
|
634
|
-
singleTypeActions.push({
|
|
635
|
-
uid: contentTypeUid,
|
|
636
|
-
action: action.type,
|
|
637
|
-
id: action.entry.id
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
642
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
643
|
-
await strapi2.db.transaction(async () => {
|
|
644
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
645
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
646
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
647
|
-
try {
|
|
648
|
-
if (action === "publish") {
|
|
649
|
-
await entityManagerService.publish(entry, uid);
|
|
650
|
-
} else {
|
|
651
|
-
await entityManagerService.unpublish(entry, uid);
|
|
652
|
-
}
|
|
653
|
-
} catch (error) {
|
|
654
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
655
|
-
} else {
|
|
656
|
-
throw error;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
661
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
662
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
663
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
664
|
-
contentTypeUid,
|
|
665
|
-
{
|
|
666
|
-
filters: {
|
|
667
|
-
id: {
|
|
668
|
-
$in: entriestoPublishIds
|
|
669
|
-
}
|
|
670
|
-
},
|
|
671
|
-
populate
|
|
672
|
-
}
|
|
673
|
-
);
|
|
674
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
675
|
-
contentTypeUid,
|
|
676
|
-
{
|
|
677
|
-
filters: {
|
|
678
|
-
id: {
|
|
679
|
-
$in: entriesToUnpublishIds
|
|
680
|
-
}
|
|
681
|
-
},
|
|
682
|
-
populate
|
|
683
|
-
}
|
|
684
|
-
);
|
|
685
|
-
if (entriesToPublish.length > 0) {
|
|
686
|
-
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);
|
|
687
974
|
}
|
|
688
|
-
|
|
689
|
-
|
|
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
|
+
);
|
|
690
982
|
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
700
|
-
},
|
|
701
|
-
populate: {
|
|
702
|
-
actions: {
|
|
703
|
-
// @ts-expect-error is not expecting count but it is working
|
|
704
|
-
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()
|
|
705
991
|
}
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
992
|
+
});
|
|
709
993
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
710
994
|
isPublished: true,
|
|
711
|
-
release:
|
|
995
|
+
release: release22
|
|
712
996
|
});
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
} catch (error) {
|
|
717
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
997
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
998
|
+
return { release: release22, error: null };
|
|
999
|
+
} catch (error2) {
|
|
718
1000
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
719
1001
|
isPublished: false,
|
|
720
|
-
error
|
|
1002
|
+
error: error2
|
|
721
1003
|
});
|
|
1004
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
1005
|
+
status: "failed"
|
|
1006
|
+
}).transacting(trx).execute();
|
|
1007
|
+
return {
|
|
1008
|
+
release: null,
|
|
1009
|
+
error: error2
|
|
1010
|
+
};
|
|
722
1011
|
}
|
|
1012
|
+
});
|
|
1013
|
+
if (error instanceof Error) {
|
|
723
1014
|
throw error;
|
|
724
1015
|
}
|
|
1016
|
+
return release2;
|
|
725
1017
|
},
|
|
726
1018
|
async updateAction(actionId, releaseId, update) {
|
|
727
1019
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -760,14 +1052,67 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
760
1052
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
761
1053
|
);
|
|
762
1054
|
}
|
|
1055
|
+
this.updateReleaseStatus(releaseId);
|
|
763
1056
|
return deletedAction;
|
|
1057
|
+
},
|
|
1058
|
+
async updateReleaseStatus(releaseId) {
|
|
1059
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
1060
|
+
this.countActions({
|
|
1061
|
+
filters: {
|
|
1062
|
+
release: releaseId
|
|
1063
|
+
}
|
|
1064
|
+
}),
|
|
1065
|
+
this.countActions({
|
|
1066
|
+
filters: {
|
|
1067
|
+
release: releaseId,
|
|
1068
|
+
isEntryValid: false
|
|
1069
|
+
}
|
|
1070
|
+
})
|
|
1071
|
+
]);
|
|
1072
|
+
if (totalActions > 0) {
|
|
1073
|
+
if (invalidActions > 0) {
|
|
1074
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1075
|
+
where: {
|
|
1076
|
+
id: releaseId
|
|
1077
|
+
},
|
|
1078
|
+
data: {
|
|
1079
|
+
status: "blocked"
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1084
|
+
where: {
|
|
1085
|
+
id: releaseId
|
|
1086
|
+
},
|
|
1087
|
+
data: {
|
|
1088
|
+
status: "ready"
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1093
|
+
where: {
|
|
1094
|
+
id: releaseId
|
|
1095
|
+
},
|
|
1096
|
+
data: {
|
|
1097
|
+
status: "empty"
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
764
1100
|
}
|
|
765
1101
|
};
|
|
766
1102
|
};
|
|
1103
|
+
class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
1104
|
+
constructor(message) {
|
|
1105
|
+
super(message);
|
|
1106
|
+
this.name = "AlreadyOnReleaseError";
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
767
1109
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
768
1110
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
769
|
-
const release2 = await strapi2.
|
|
770
|
-
|
|
1111
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1112
|
+
where: {
|
|
1113
|
+
id: releaseId
|
|
1114
|
+
},
|
|
1115
|
+
populate: { actions: { populate: { entry: { select: ["id"] } } } }
|
|
771
1116
|
});
|
|
772
1117
|
if (!release2) {
|
|
773
1118
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -776,7 +1121,7 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
776
1121
|
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
777
1122
|
);
|
|
778
1123
|
if (isEntryInRelease) {
|
|
779
|
-
throw new
|
|
1124
|
+
throw new AlreadyOnReleaseError(
|
|
780
1125
|
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
781
1126
|
);
|
|
782
1127
|
}
|
|
@@ -793,10 +1138,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
793
1138
|
}
|
|
794
1139
|
},
|
|
795
1140
|
async validatePendingReleasesLimit() {
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
799
|
-
);
|
|
1141
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1142
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
800
1143
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
801
1144
|
filters: {
|
|
802
1145
|
releasedAt: {
|
|
@@ -809,8 +1152,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
809
1152
|
}
|
|
810
1153
|
},
|
|
811
1154
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
812
|
-
const pendingReleases = await strapi2.
|
|
813
|
-
|
|
1155
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1156
|
+
where: {
|
|
814
1157
|
releasedAt: {
|
|
815
1158
|
$null: true
|
|
816
1159
|
},
|
|
@@ -839,7 +1182,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
839
1182
|
}
|
|
840
1183
|
const job = scheduleJob(scheduleDate, async () => {
|
|
841
1184
|
try {
|
|
842
|
-
await getService("release").publish(releaseId);
|
|
1185
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
843
1186
|
} catch (error) {
|
|
844
1187
|
}
|
|
845
1188
|
this.cancel(releaseId);
|
|
@@ -884,7 +1227,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
884
1227
|
const services = {
|
|
885
1228
|
release: createReleaseService,
|
|
886
1229
|
"release-validation": createReleaseValidationService,
|
|
887
|
-
|
|
1230
|
+
scheduling: createSchedulingService
|
|
888
1231
|
};
|
|
889
1232
|
const RELEASE_SCHEMA = yup.object().shape({
|
|
890
1233
|
name: yup.string().trim().required(),
|
|
@@ -909,7 +1252,7 @@ const RELEASE_SCHEMA = yup.object().shape({
|
|
|
909
1252
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
910
1253
|
const releaseController = {
|
|
911
1254
|
async findMany(ctx) {
|
|
912
|
-
const permissionsManager = strapi.admin
|
|
1255
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
913
1256
|
ability: ctx.state.userAbility,
|
|
914
1257
|
model: RELEASE_MODEL_UID
|
|
915
1258
|
});
|
|
@@ -937,7 +1280,12 @@ const releaseController = {
|
|
|
937
1280
|
}
|
|
938
1281
|
};
|
|
939
1282
|
});
|
|
940
|
-
|
|
1283
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1284
|
+
where: {
|
|
1285
|
+
releasedAt: null
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
941
1289
|
}
|
|
942
1290
|
},
|
|
943
1291
|
async findOne(ctx) {
|
|
@@ -954,7 +1302,7 @@ const releaseController = {
|
|
|
954
1302
|
});
|
|
955
1303
|
const sanitizedRelease = {
|
|
956
1304
|
...release2,
|
|
957
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1305
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
958
1306
|
};
|
|
959
1307
|
const data = {
|
|
960
1308
|
...sanitizedRelease,
|
|
@@ -966,19 +1314,48 @@ const releaseController = {
|
|
|
966
1314
|
};
|
|
967
1315
|
ctx.body = { data };
|
|
968
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
|
+
},
|
|
969
1346
|
async create(ctx) {
|
|
970
1347
|
const user = ctx.state.user;
|
|
971
1348
|
const releaseArgs = ctx.request.body;
|
|
972
1349
|
await validateRelease(releaseArgs);
|
|
973
1350
|
const releaseService = getService("release", { strapi });
|
|
974
1351
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
975
|
-
const permissionsManager = strapi.admin
|
|
1352
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
976
1353
|
ability: ctx.state.userAbility,
|
|
977
1354
|
model: RELEASE_MODEL_UID
|
|
978
1355
|
});
|
|
979
|
-
ctx.
|
|
1356
|
+
ctx.created({
|
|
980
1357
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
981
|
-
};
|
|
1358
|
+
});
|
|
982
1359
|
},
|
|
983
1360
|
async update(ctx) {
|
|
984
1361
|
const user = ctx.state.user;
|
|
@@ -987,7 +1364,7 @@ const releaseController = {
|
|
|
987
1364
|
await validateRelease(releaseArgs);
|
|
988
1365
|
const releaseService = getService("release", { strapi });
|
|
989
1366
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
990
|
-
const permissionsManager = strapi.admin
|
|
1367
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
991
1368
|
ability: ctx.state.userAbility,
|
|
992
1369
|
model: RELEASE_MODEL_UID
|
|
993
1370
|
});
|
|
@@ -1051,13 +1428,45 @@ const releaseActionController = {
|
|
|
1051
1428
|
await validateReleaseAction(releaseActionArgs);
|
|
1052
1429
|
const releaseService = getService("release", { strapi });
|
|
1053
1430
|
const releaseAction2 = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1054
|
-
ctx.
|
|
1431
|
+
ctx.created({
|
|
1055
1432
|
data: releaseAction2
|
|
1056
|
-
};
|
|
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
|
+
});
|
|
1057
1466
|
},
|
|
1058
1467
|
async findMany(ctx) {
|
|
1059
1468
|
const releaseId = ctx.params.releaseId;
|
|
1060
|
-
const permissionsManager = strapi.admin
|
|
1469
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1061
1470
|
ability: ctx.state.userAbility,
|
|
1062
1471
|
model: RELEASE_ACTION_MODEL_UID
|
|
1063
1472
|
});
|
|
@@ -1071,14 +1480,14 @@ const releaseActionController = {
|
|
|
1071
1480
|
if (acc[action.contentType]) {
|
|
1072
1481
|
return acc;
|
|
1073
1482
|
}
|
|
1074
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1483
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1075
1484
|
ability: ctx.state.userAbility,
|
|
1076
1485
|
model: action.contentType
|
|
1077
1486
|
});
|
|
1078
1487
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1079
1488
|
return acc;
|
|
1080
1489
|
}, {});
|
|
1081
|
-
const sanitizedResults = await
|
|
1490
|
+
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1082
1491
|
...action,
|
|
1083
1492
|
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1084
1493
|
}));
|
|
@@ -1123,6 +1532,22 @@ const controllers = { release: releaseController, "release-action": releaseActio
|
|
|
1123
1532
|
const release = {
|
|
1124
1533
|
type: "admin",
|
|
1125
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
|
+
},
|
|
1126
1551
|
{
|
|
1127
1552
|
method: "POST",
|
|
1128
1553
|
path: "/",
|
|
@@ -1240,6 +1665,22 @@ const releaseAction = {
|
|
|
1240
1665
|
]
|
|
1241
1666
|
}
|
|
1242
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
|
+
},
|
|
1243
1684
|
{
|
|
1244
1685
|
method: "GET",
|
|
1245
1686
|
path: "/:releaseId/actions",
|
|
@@ -1294,9 +1735,8 @@ const routes = {
|
|
|
1294
1735
|
release,
|
|
1295
1736
|
"release-action": releaseAction
|
|
1296
1737
|
};
|
|
1297
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1298
1738
|
const getPlugin = () => {
|
|
1299
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1739
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1300
1740
|
return {
|
|
1301
1741
|
register,
|
|
1302
1742
|
bootstrap,
|
|
@@ -1308,6 +1748,9 @@ const getPlugin = () => {
|
|
|
1308
1748
|
};
|
|
1309
1749
|
}
|
|
1310
1750
|
return {
|
|
1751
|
+
// Always return register, it handles its own feature check
|
|
1752
|
+
register,
|
|
1753
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1311
1754
|
contentTypes
|
|
1312
1755
|
};
|
|
1313
1756
|
};
|