@strapi/content-releases 0.0.0-next.836f74517f9a428a4798ed889c3f05057ec6beb1 → 0.0.0-next.840550dc97a3782302ddf918d3a0d07e59dd11eb
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/LICENSE +17 -1
- package/dist/_chunks/App-BKB1esYS.js +1395 -0
- package/dist/_chunks/App-BKB1esYS.js.map +1 -0
- package/dist/_chunks/{App-fcvNs2Qb.mjs → App-Cne--1Z8.mjs} +588 -536
- package/dist/_chunks/App-Cne--1Z8.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/ReleasesSettingsPage-C1WwGWIH.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js.map +1 -0
- package/dist/_chunks/{en-gcJJ5htG.js → en-CmYoEnA7.js} +19 -4
- package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
- package/dist/_chunks/{en-WuuhP6Bn.mjs → en-D0yVZFqf.mjs} +19 -4
- package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
- package/dist/_chunks/index-5Odi61vw.js +1381 -0
- package/dist/_chunks/index-5Odi61vw.js.map +1 -0
- package/dist/_chunks/index-Cy7qwpaU.mjs +1362 -0
- package/dist/_chunks/index-Cy7qwpaU.mjs.map +1 -0
- package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
- package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
- package/dist/_chunks/schemas-DdA2ic2U.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/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/ReleaseActionModal.d.ts +24 -0
- package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
- package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
- package/dist/admin/src/components/ReleaseModal.d.ts +17 -0
- package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
- package/dist/admin/src/constants.d.ts +76 -0
- package/dist/admin/src/index.d.ts +3 -0
- package/dist/admin/src/modules/hooks.d.ts +7 -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/ReleasesSettingsPage.d.ts +1 -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 +112 -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 +10 -0
- package/dist/admin/src/validation/schemas.d.ts +6 -0
- package/dist/server/index.js +1000 -665
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1001 -665
- 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 +21 -0
- package/dist/server/src/constants.d.ts.map +1 -0
- package/dist/server/src/content-types/index.d.ts +97 -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 +48 -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 +47 -0
- package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
- package/dist/server/src/controllers/index.d.ts +25 -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 +18 -0
- package/dist/server/src/controllers/release.d.ts.map +1 -0
- package/dist/server/src/controllers/settings.d.ts +11 -0
- package/dist/server/src/controllers/settings.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release-action.d.ts +14 -0
- package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release.d.ts +4 -0
- package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/settings.d.ts +3 -0
- package/dist/server/src/controllers/validation/settings.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 +2115 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/middlewares/documents.d.ts +6 -0
- package/dist/server/src/middlewares/documents.d.ts.map +1 -0
- package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
- package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.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 +51 -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/routes/settings.d.ts +18 -0
- package/dist/server/src/routes/settings.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +1828 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/release-action.d.ts +38 -0
- package/dist/server/src/services/release-action.d.ts.map +1 -0
- package/dist/server/src/services/release.d.ts +31 -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/settings.d.ts +13 -0
- package/dist/server/src/services/settings.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 +35 -0
- package/dist/server/src/utils/index.d.ts.map +1 -0
- package/dist/shared/contracts/release-actions.d.ts +130 -0
- package/dist/shared/contracts/release-actions.d.ts.map +1 -0
- package/dist/shared/contracts/releases.d.ts +184 -0
- package/dist/shared/contracts/releases.d.ts.map +1 -0
- package/dist/shared/contracts/settings.d.ts +39 -0
- package/dist/shared/contracts/settings.d.ts.map +1 -0
- package/dist/shared/types.d.ts +24 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/package.json +33 -38
- package/dist/_chunks/App-fcvNs2Qb.mjs.map +0 -1
- package/dist/_chunks/App-pNsURCL_.js +0 -1345
- package/dist/_chunks/App-pNsURCL_.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-gzTuOXiK.js +0 -1034
- package/dist/_chunks/index-gzTuOXiK.js.map +0 -1
- package/dist/_chunks/index-pxhi8wsT.mjs +0 -1013
- package/dist/_chunks/index-pxhi8wsT.mjs.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.js
CHANGED
|
@@ -3,7 +3,6 @@ const utils = require("@strapi/utils");
|
|
|
3
3
|
const isEqual = require("lodash/isEqual");
|
|
4
4
|
const lodash = require("lodash");
|
|
5
5
|
const _ = require("lodash/fp");
|
|
6
|
-
const EE = require("@strapi/strapi/dist/utils/ee");
|
|
7
6
|
const nodeSchedule = require("node-schedule");
|
|
8
7
|
const yup = require("yup");
|
|
9
8
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -27,7 +26,6 @@ function _interopNamespace(e) {
|
|
|
27
26
|
}
|
|
28
27
|
const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
|
|
29
28
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
30
|
-
const EE__default = /* @__PURE__ */ _interopDefault(EE);
|
|
31
29
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
32
30
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
33
31
|
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
@@ -73,21 +71,38 @@ const ACTIONS = [
|
|
|
73
71
|
displayName: "Add an entry to a release",
|
|
74
72
|
uid: "create-action",
|
|
75
73
|
pluginName: "content-releases"
|
|
74
|
+
},
|
|
75
|
+
// Settings
|
|
76
|
+
{
|
|
77
|
+
uid: "settings.read",
|
|
78
|
+
section: "settings",
|
|
79
|
+
displayName: "Read",
|
|
80
|
+
category: "content releases",
|
|
81
|
+
subCategory: "options",
|
|
82
|
+
pluginName: "content-releases"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
uid: "settings.update",
|
|
86
|
+
section: "settings",
|
|
87
|
+
displayName: "Edit",
|
|
88
|
+
category: "content releases",
|
|
89
|
+
subCategory: "options",
|
|
90
|
+
pluginName: "content-releases"
|
|
76
91
|
}
|
|
77
92
|
];
|
|
78
93
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
79
94
|
RELEASES_PUBLISH: "releases.publish"
|
|
80
95
|
};
|
|
81
|
-
const getService = (name, { strapi: strapi2 }
|
|
96
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
82
97
|
return strapi2.plugin("content-releases").service(name);
|
|
83
98
|
};
|
|
84
|
-
const
|
|
99
|
+
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi: strapi2 }) => {
|
|
85
100
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
86
|
-
const populate = await populateBuilderService(
|
|
87
|
-
const entry = await
|
|
88
|
-
return entry;
|
|
101
|
+
const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();
|
|
102
|
+
const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi: strapi2 });
|
|
103
|
+
return isEntryValid(contentType, entry, { strapi: strapi2 });
|
|
89
104
|
};
|
|
90
|
-
const
|
|
105
|
+
const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
91
106
|
try {
|
|
92
107
|
await strapi2.entityValidator.validateEntityCreation(
|
|
93
108
|
strapi2.getModel(contentTypeUid),
|
|
@@ -101,6 +116,38 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
101
116
|
return false;
|
|
102
117
|
}
|
|
103
118
|
};
|
|
119
|
+
const getEntry = async ({
|
|
120
|
+
contentType,
|
|
121
|
+
documentId,
|
|
122
|
+
locale,
|
|
123
|
+
populate,
|
|
124
|
+
status = "draft"
|
|
125
|
+
}, { strapi: strapi2 }) => {
|
|
126
|
+
if (documentId) {
|
|
127
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
128
|
+
}
|
|
129
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
130
|
+
};
|
|
131
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
132
|
+
if (entry.publishedAt) {
|
|
133
|
+
return "published";
|
|
134
|
+
}
|
|
135
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
136
|
+
documentId: entry.documentId,
|
|
137
|
+
locale: entry.locale,
|
|
138
|
+
status: "published",
|
|
139
|
+
fields: ["updatedAt"]
|
|
140
|
+
});
|
|
141
|
+
if (!publishedEntry) {
|
|
142
|
+
return "draft";
|
|
143
|
+
}
|
|
144
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
145
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
146
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
147
|
+
return "modified";
|
|
148
|
+
}
|
|
149
|
+
return "published";
|
|
150
|
+
};
|
|
104
151
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
105
152
|
oldContentTypes,
|
|
106
153
|
contentTypes: contentTypes2
|
|
@@ -122,7 +169,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
122
169
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
123
170
|
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
124
171
|
if (deletedContentTypes.length) {
|
|
125
|
-
await utils.
|
|
172
|
+
await utils.async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
126
173
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
127
174
|
});
|
|
128
175
|
}
|
|
@@ -141,25 +188,27 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
141
188
|
}
|
|
142
189
|
}
|
|
143
190
|
});
|
|
144
|
-
utils.
|
|
191
|
+
utils.async.map(releasesWithoutStatus, async (release2) => {
|
|
145
192
|
const actions = release2.actions;
|
|
146
193
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
147
194
|
for (const action of notValidatedActions) {
|
|
148
195
|
if (action.entry) {
|
|
149
|
-
const
|
|
150
|
-
|
|
196
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
197
|
+
{
|
|
198
|
+
contentType: action.contentType,
|
|
199
|
+
documentId: action.entryDocumentId,
|
|
200
|
+
locale: action.locale
|
|
201
|
+
},
|
|
202
|
+
{ strapi }
|
|
203
|
+
);
|
|
204
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
205
|
+
where: {
|
|
206
|
+
id: action.id
|
|
207
|
+
},
|
|
208
|
+
data: {
|
|
209
|
+
isEntryValid: isEntryValid2
|
|
210
|
+
}
|
|
151
211
|
});
|
|
152
|
-
if (populatedEntry) {
|
|
153
|
-
const isEntryValid = getEntryValidStatus(action.contentType, populatedEntry, { strapi });
|
|
154
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
155
|
-
where: {
|
|
156
|
-
id: action.id
|
|
157
|
-
},
|
|
158
|
-
data: {
|
|
159
|
-
isEntryValid
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
212
|
}
|
|
164
213
|
}
|
|
165
214
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -172,7 +221,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
172
221
|
}
|
|
173
222
|
}
|
|
174
223
|
});
|
|
175
|
-
utils.
|
|
224
|
+
utils.async.map(publishedReleases, async (release2) => {
|
|
176
225
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
177
226
|
where: {
|
|
178
227
|
id: release2.id
|
|
@@ -189,7 +238,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
189
238
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
190
239
|
);
|
|
191
240
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
192
|
-
utils.
|
|
241
|
+
utils.async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
193
242
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
194
243
|
const contentType = contentTypes2[contentTypeUID];
|
|
195
244
|
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -202,30 +251,30 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
202
251
|
release: true
|
|
203
252
|
}
|
|
204
253
|
});
|
|
205
|
-
await utils.
|
|
206
|
-
if (action.entry && action.release) {
|
|
207
|
-
const
|
|
208
|
-
|
|
254
|
+
await utils.async.map(actions, async (action) => {
|
|
255
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
256
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
257
|
+
{
|
|
258
|
+
contentType: contentTypeUID,
|
|
259
|
+
documentId: action.entryDocumentId,
|
|
260
|
+
locale: action.locale
|
|
261
|
+
},
|
|
262
|
+
{ strapi }
|
|
263
|
+
);
|
|
264
|
+
releasesAffected.add(action.release.id);
|
|
265
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
266
|
+
where: {
|
|
267
|
+
id: action.id
|
|
268
|
+
},
|
|
269
|
+
data: {
|
|
270
|
+
isEntryValid: isEntryValid2
|
|
271
|
+
}
|
|
209
272
|
});
|
|
210
|
-
if (populatedEntry) {
|
|
211
|
-
const isEntryValid = await getEntryValidStatus(contentTypeUID, populatedEntry, {
|
|
212
|
-
strapi
|
|
213
|
-
});
|
|
214
|
-
releasesAffected.add(action.release.id);
|
|
215
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
216
|
-
where: {
|
|
217
|
-
id: action.id
|
|
218
|
-
},
|
|
219
|
-
data: {
|
|
220
|
-
isEntryValid
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
273
|
}
|
|
225
274
|
});
|
|
226
275
|
}
|
|
227
276
|
}).then(() => {
|
|
228
|
-
utils.
|
|
277
|
+
utils.async.map(releasesAffected, async (releaseId) => {
|
|
229
278
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
230
279
|
});
|
|
231
280
|
});
|
|
@@ -235,13 +284,16 @@ async function disableContentTypeLocalized({ oldContentTypes, contentTypes: cont
|
|
|
235
284
|
if (!oldContentTypes) {
|
|
236
285
|
return;
|
|
237
286
|
}
|
|
287
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
288
|
+
if (!i18nPlugin) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
238
291
|
for (const uid in contentTypes2) {
|
|
239
292
|
if (!oldContentTypes[uid]) {
|
|
240
293
|
continue;
|
|
241
294
|
}
|
|
242
295
|
const oldContentType = oldContentTypes[uid];
|
|
243
296
|
const contentType = contentTypes2[uid];
|
|
244
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
245
297
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
246
298
|
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
247
299
|
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -254,13 +306,16 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
254
306
|
if (!oldContentTypes) {
|
|
255
307
|
return;
|
|
256
308
|
}
|
|
309
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
310
|
+
if (!i18nPlugin) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
257
313
|
for (const uid in contentTypes2) {
|
|
258
314
|
if (!oldContentTypes[uid]) {
|
|
259
315
|
continue;
|
|
260
316
|
}
|
|
261
317
|
const oldContentType = oldContentTypes[uid];
|
|
262
318
|
const contentType = contentTypes2[uid];
|
|
263
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
264
319
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
265
320
|
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
266
321
|
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
@@ -271,158 +326,196 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
271
326
|
}
|
|
272
327
|
}
|
|
273
328
|
}
|
|
274
|
-
const
|
|
329
|
+
const addEntryDocumentToReleaseActions = {
|
|
330
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
331
|
+
async up(trx, db) {
|
|
332
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
333
|
+
if (!hasTable) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
337
|
+
if (hasPolymorphicColumn) {
|
|
338
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
339
|
+
"strapi_release_actions",
|
|
340
|
+
"entry_document_id"
|
|
341
|
+
);
|
|
342
|
+
if (!hasEntryDocumentIdColumn) {
|
|
343
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
344
|
+
table.string("entry_document_id");
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
348
|
+
utils.async.map(releaseActions, async (action) => {
|
|
349
|
+
const { target_type, target_id } = action;
|
|
350
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
351
|
+
if (entry) {
|
|
352
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
async down() {
|
|
358
|
+
throw new Error("not implemented");
|
|
359
|
+
}
|
|
360
|
+
};
|
|
275
361
|
const register = async ({ strapi: strapi2 }) => {
|
|
276
|
-
if (features
|
|
277
|
-
await strapi2.admin
|
|
278
|
-
strapi2.
|
|
362
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
363
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
364
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
365
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
279
366
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
280
367
|
}
|
|
368
|
+
if (strapi2.plugin("graphql")) {
|
|
369
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
370
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
371
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
375
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
376
|
+
where: {
|
|
377
|
+
actions: {
|
|
378
|
+
contentType,
|
|
379
|
+
entryDocumentId: entry.documentId,
|
|
380
|
+
locale: entry.locale
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
385
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
386
|
+
where: {
|
|
387
|
+
contentType,
|
|
388
|
+
entryDocumentId: entry.documentId,
|
|
389
|
+
locale: entry.locale
|
|
390
|
+
},
|
|
391
|
+
data: {
|
|
392
|
+
isEntryValid: entryStatus
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
for (const release2 of releases) {
|
|
396
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
400
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
401
|
+
where: {
|
|
402
|
+
actions: params
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
406
|
+
where: params
|
|
407
|
+
});
|
|
408
|
+
for (const release2 of releases) {
|
|
409
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
413
|
+
if (ctx.action !== "delete") {
|
|
414
|
+
return next();
|
|
415
|
+
}
|
|
416
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
417
|
+
return next();
|
|
418
|
+
}
|
|
419
|
+
const contentType = ctx.contentType.uid;
|
|
420
|
+
const { documentId, locale } = ctx.params;
|
|
421
|
+
const result = await next();
|
|
422
|
+
if (!result) {
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
427
|
+
contentType,
|
|
428
|
+
entryDocumentId: documentId,
|
|
429
|
+
...locale !== "*" && { locale }
|
|
430
|
+
});
|
|
431
|
+
} catch (error) {
|
|
432
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
433
|
+
error
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return result;
|
|
437
|
+
};
|
|
438
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
439
|
+
if (ctx.action !== "update") {
|
|
440
|
+
return next();
|
|
441
|
+
}
|
|
442
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
443
|
+
return next();
|
|
444
|
+
}
|
|
445
|
+
const contentType = ctx.contentType.uid;
|
|
446
|
+
const result = await next();
|
|
447
|
+
if (!result) {
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
try {
|
|
451
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
454
|
+
error
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
return result;
|
|
458
|
+
};
|
|
459
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
460
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
461
|
+
where: {
|
|
462
|
+
actions: params
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
466
|
+
where: params
|
|
467
|
+
});
|
|
468
|
+
for (const release2 of releases) {
|
|
469
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
470
|
+
}
|
|
281
471
|
};
|
|
282
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
283
472
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
284
|
-
if (features
|
|
473
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
285
474
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
286
475
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
287
476
|
);
|
|
288
477
|
strapi2.db.lifecycles.subscribe({
|
|
289
478
|
models: contentTypesWithDraftAndPublish,
|
|
290
|
-
async afterDelete(event) {
|
|
291
|
-
try {
|
|
292
|
-
const { model, result } = event;
|
|
293
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
294
|
-
const { id } = result;
|
|
295
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
296
|
-
where: {
|
|
297
|
-
actions: {
|
|
298
|
-
target_type: model.uid,
|
|
299
|
-
target_id: id
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
304
|
-
where: {
|
|
305
|
-
target_type: model.uid,
|
|
306
|
-
target_id: id
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
for (const release2 of releases) {
|
|
310
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
} catch (error) {
|
|
314
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
/**
|
|
318
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
319
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
320
|
-
*/
|
|
321
|
-
async beforeDeleteMany(event) {
|
|
322
|
-
const { model, params } = event;
|
|
323
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
324
|
-
const { where } = params;
|
|
325
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
326
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
479
|
/**
|
|
330
|
-
*
|
|
331
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
480
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
332
481
|
*/
|
|
333
482
|
async afterDeleteMany(event) {
|
|
334
483
|
try {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
target_id: {
|
|
343
|
-
$in: entriesToDelete.map(
|
|
344
|
-
(entry) => entry.id
|
|
345
|
-
)
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
351
|
-
where: {
|
|
352
|
-
target_type: model.uid,
|
|
353
|
-
target_id: {
|
|
354
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
484
|
+
const model = strapi2.getModel(event.model.uid);
|
|
485
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
486
|
+
const { where } = event.params;
|
|
487
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
488
|
+
contentType: model.uid,
|
|
489
|
+
locale: where.locale ?? null,
|
|
490
|
+
...where.documentId && { entryDocumentId: where.documentId }
|
|
357
491
|
});
|
|
358
|
-
for (const release2 of releases) {
|
|
359
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
360
|
-
}
|
|
361
492
|
}
|
|
362
493
|
} catch (error) {
|
|
363
494
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
364
495
|
error
|
|
365
496
|
});
|
|
366
497
|
}
|
|
367
|
-
},
|
|
368
|
-
async afterUpdate(event) {
|
|
369
|
-
try {
|
|
370
|
-
const { model, result } = event;
|
|
371
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
372
|
-
const isEntryValid = await getEntryValidStatus(
|
|
373
|
-
model.uid,
|
|
374
|
-
result,
|
|
375
|
-
{
|
|
376
|
-
strapi: strapi2
|
|
377
|
-
}
|
|
378
|
-
);
|
|
379
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
380
|
-
where: {
|
|
381
|
-
target_type: model.uid,
|
|
382
|
-
target_id: result.id
|
|
383
|
-
},
|
|
384
|
-
data: {
|
|
385
|
-
isEntryValid
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
389
|
-
where: {
|
|
390
|
-
actions: {
|
|
391
|
-
target_type: model.uid,
|
|
392
|
-
target_id: result.id
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
for (const release2 of releases) {
|
|
397
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
} catch (error) {
|
|
401
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
402
|
-
}
|
|
403
498
|
}
|
|
404
499
|
});
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
500
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
501
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
502
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
503
|
+
strapi2.log.error(
|
|
504
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
505
|
+
);
|
|
506
|
+
throw err;
|
|
507
|
+
});
|
|
508
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
509
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
510
|
+
});
|
|
416
511
|
}
|
|
417
512
|
};
|
|
418
513
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
job.cancel();
|
|
425
|
-
}
|
|
514
|
+
const scheduledJobs = getService("scheduling", {
|
|
515
|
+
strapi: strapi2
|
|
516
|
+
}).getAll();
|
|
517
|
+
for (const [, job] of scheduledJobs) {
|
|
518
|
+
job.cancel();
|
|
426
519
|
}
|
|
427
520
|
};
|
|
428
521
|
const schema$1 = {
|
|
@@ -497,15 +590,13 @@ const schema = {
|
|
|
497
590
|
enum: ["publish", "unpublish"],
|
|
498
591
|
required: true
|
|
499
592
|
},
|
|
500
|
-
entry: {
|
|
501
|
-
type: "relation",
|
|
502
|
-
relation: "morphToOne",
|
|
503
|
-
configurable: false
|
|
504
|
-
},
|
|
505
593
|
contentType: {
|
|
506
594
|
type: "string",
|
|
507
595
|
required: true
|
|
508
596
|
},
|
|
597
|
+
entryDocumentId: {
|
|
598
|
+
type: "string"
|
|
599
|
+
},
|
|
509
600
|
locale: {
|
|
510
601
|
type: "string"
|
|
511
602
|
},
|
|
@@ -527,18 +618,6 @@ const contentTypes = {
|
|
|
527
618
|
release: release$1,
|
|
528
619
|
"release-action": releaseAction$1
|
|
529
620
|
};
|
|
530
|
-
const getGroupName = (queryValue) => {
|
|
531
|
-
switch (queryValue) {
|
|
532
|
-
case "contentType":
|
|
533
|
-
return "contentType.displayName";
|
|
534
|
-
case "action":
|
|
535
|
-
return "type";
|
|
536
|
-
case "locale":
|
|
537
|
-
return ___default.default.getOr("No locale", "locale.name");
|
|
538
|
-
default:
|
|
539
|
-
return "contentType.displayName";
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
621
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
543
622
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
544
623
|
strapi2.eventHub.emit(event, {
|
|
@@ -547,6 +626,33 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
547
626
|
release: release2
|
|
548
627
|
});
|
|
549
628
|
};
|
|
629
|
+
const getFormattedActions = async (releaseId) => {
|
|
630
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
631
|
+
where: {
|
|
632
|
+
release: {
|
|
633
|
+
id: releaseId
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
if (actions.length === 0) {
|
|
638
|
+
throw new utils.errors.ValidationError("No entries to publish");
|
|
639
|
+
}
|
|
640
|
+
const formattedActions = {};
|
|
641
|
+
for (const action of actions) {
|
|
642
|
+
const contentTypeUid = action.contentType;
|
|
643
|
+
if (!formattedActions[contentTypeUid]) {
|
|
644
|
+
formattedActions[contentTypeUid] = {
|
|
645
|
+
publish: [],
|
|
646
|
+
unpublish: []
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
650
|
+
documentId: action.entryDocumentId,
|
|
651
|
+
locale: action.locale
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
return formattedActions;
|
|
655
|
+
};
|
|
550
656
|
return {
|
|
551
657
|
async create(releaseData, { user }) {
|
|
552
658
|
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
@@ -560,13 +666,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
560
666
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
561
667
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
562
668
|
]);
|
|
563
|
-
const release2 = await strapi2.
|
|
669
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
564
670
|
data: {
|
|
565
671
|
...releaseWithCreatorFields,
|
|
566
672
|
status: "empty"
|
|
567
673
|
}
|
|
568
674
|
});
|
|
569
|
-
if (
|
|
675
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
570
676
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
571
677
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
572
678
|
}
|
|
@@ -574,94 +680,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
574
680
|
return release2;
|
|
575
681
|
},
|
|
576
682
|
async findOne(id, query = {}) {
|
|
577
|
-
const
|
|
578
|
-
|
|
683
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
684
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
685
|
+
...dbQuery,
|
|
686
|
+
where: { id }
|
|
579
687
|
});
|
|
580
688
|
return release2;
|
|
581
689
|
},
|
|
582
690
|
findPage(query) {
|
|
583
|
-
|
|
584
|
-
|
|
691
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
692
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
693
|
+
...dbQuery,
|
|
585
694
|
populate: {
|
|
586
695
|
actions: {
|
|
587
|
-
// @ts-expect-error Ignore missing properties
|
|
588
696
|
count: true
|
|
589
697
|
}
|
|
590
698
|
}
|
|
591
699
|
});
|
|
592
700
|
},
|
|
593
|
-
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
target_type: contentTypeUid,
|
|
598
|
-
target_id: entryId
|
|
599
|
-
},
|
|
600
|
-
releasedAt: {
|
|
601
|
-
$null: true
|
|
602
|
-
}
|
|
603
|
-
},
|
|
604
|
-
populate: {
|
|
605
|
-
// Filter the action to get only the content type entry
|
|
606
|
-
actions: {
|
|
607
|
-
where: {
|
|
608
|
-
target_type: contentTypeUid,
|
|
609
|
-
target_id: entryId
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
return releases.map((release2) => {
|
|
615
|
-
if (release2.actions?.length) {
|
|
616
|
-
const [actionForEntry] = release2.actions;
|
|
617
|
-
delete release2.actions;
|
|
618
|
-
return {
|
|
619
|
-
...release2,
|
|
620
|
-
action: actionForEntry
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
return release2;
|
|
624
|
-
});
|
|
625
|
-
},
|
|
626
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
627
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
628
|
-
where: {
|
|
629
|
-
releasedAt: {
|
|
630
|
-
$null: true
|
|
631
|
-
},
|
|
632
|
-
actions: {
|
|
633
|
-
target_type: contentTypeUid,
|
|
634
|
-
target_id: entryId
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
639
|
-
where: {
|
|
640
|
-
$or: [
|
|
641
|
-
{
|
|
642
|
-
id: {
|
|
643
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
644
|
-
}
|
|
645
|
-
},
|
|
646
|
-
{
|
|
647
|
-
actions: null
|
|
648
|
-
}
|
|
649
|
-
],
|
|
650
|
-
releasedAt: {
|
|
651
|
-
$null: true
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
});
|
|
655
|
-
return releases.map((release2) => {
|
|
656
|
-
if (release2.actions?.length) {
|
|
657
|
-
const [actionForEntry] = release2.actions;
|
|
658
|
-
delete release2.actions;
|
|
659
|
-
return {
|
|
660
|
-
...release2,
|
|
661
|
-
action: actionForEntry
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
return release2;
|
|
701
|
+
findMany(query) {
|
|
702
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
703
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
704
|
+
...dbQuery
|
|
665
705
|
});
|
|
666
706
|
},
|
|
667
707
|
async update(id, releaseData, { user }) {
|
|
@@ -676,90 +716,307 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
676
716
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
677
717
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
678
718
|
]);
|
|
679
|
-
const release2 = await strapi2.
|
|
719
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
680
720
|
if (!release2) {
|
|
681
721
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
682
722
|
}
|
|
683
723
|
if (release2.releasedAt) {
|
|
684
724
|
throw new utils.errors.ValidationError("Release already published");
|
|
685
725
|
}
|
|
686
|
-
const updatedRelease = await strapi2.
|
|
687
|
-
|
|
688
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
689
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
690
|
-
*/
|
|
691
|
-
// @ts-expect-error see above
|
|
726
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
727
|
+
where: { id },
|
|
692
728
|
data: releaseWithCreatorFields
|
|
693
729
|
});
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
schedulingService.cancel(id);
|
|
700
|
-
}
|
|
730
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
731
|
+
if (releaseData.scheduledAt) {
|
|
732
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
733
|
+
} else if (release2.scheduledAt) {
|
|
734
|
+
schedulingService.cancel(id);
|
|
701
735
|
}
|
|
702
736
|
this.updateReleaseStatus(id);
|
|
703
737
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
704
738
|
return updatedRelease;
|
|
705
739
|
},
|
|
706
|
-
async
|
|
707
|
-
const
|
|
740
|
+
async getAllComponents() {
|
|
741
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
742
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
743
|
+
const componentsMap = components.reduce(
|
|
744
|
+
(acc, component) => {
|
|
745
|
+
acc[component.uid] = component;
|
|
746
|
+
return acc;
|
|
747
|
+
},
|
|
748
|
+
{}
|
|
749
|
+
);
|
|
750
|
+
return componentsMap;
|
|
751
|
+
},
|
|
752
|
+
async delete(releaseId) {
|
|
753
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
754
|
+
where: { id: releaseId },
|
|
755
|
+
populate: {
|
|
756
|
+
actions: {
|
|
757
|
+
select: ["id"]
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
if (!release2) {
|
|
762
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
763
|
+
}
|
|
764
|
+
if (release2.releasedAt) {
|
|
765
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
766
|
+
}
|
|
767
|
+
await strapi2.db.transaction(async () => {
|
|
768
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
769
|
+
where: {
|
|
770
|
+
id: {
|
|
771
|
+
$in: release2.actions.map((action) => action.id)
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
776
|
+
where: {
|
|
777
|
+
id: releaseId
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
if (release2.scheduledAt) {
|
|
782
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
783
|
+
await schedulingService.cancel(release2.id);
|
|
784
|
+
}
|
|
785
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
786
|
+
return release2;
|
|
787
|
+
},
|
|
788
|
+
async publish(releaseId) {
|
|
789
|
+
const {
|
|
790
|
+
release: release2,
|
|
791
|
+
error
|
|
792
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
793
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
794
|
+
if (!lockedRelease) {
|
|
795
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
796
|
+
}
|
|
797
|
+
if (lockedRelease.releasedAt) {
|
|
798
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
799
|
+
}
|
|
800
|
+
if (lockedRelease.status === "failed") {
|
|
801
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
802
|
+
}
|
|
803
|
+
try {
|
|
804
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
805
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
806
|
+
await strapi2.db.transaction(
|
|
807
|
+
async () => Promise.all(
|
|
808
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
809
|
+
const contentType = contentTypeUid;
|
|
810
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
811
|
+
return Promise.all([
|
|
812
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
813
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
814
|
+
]);
|
|
815
|
+
})
|
|
816
|
+
)
|
|
817
|
+
);
|
|
818
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
819
|
+
where: {
|
|
820
|
+
id: releaseId
|
|
821
|
+
},
|
|
822
|
+
data: {
|
|
823
|
+
status: "done",
|
|
824
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
828
|
+
isPublished: true,
|
|
829
|
+
release: release22
|
|
830
|
+
});
|
|
831
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
832
|
+
return { release: release22, error: null };
|
|
833
|
+
} catch (error2) {
|
|
834
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
835
|
+
isPublished: false,
|
|
836
|
+
error: error2
|
|
837
|
+
});
|
|
838
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
839
|
+
status: "failed"
|
|
840
|
+
}).transacting(trx).execute();
|
|
841
|
+
return {
|
|
842
|
+
release: null,
|
|
843
|
+
error: error2
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
if (error instanceof Error) {
|
|
848
|
+
throw error;
|
|
849
|
+
}
|
|
850
|
+
return release2;
|
|
851
|
+
},
|
|
852
|
+
async updateReleaseStatus(releaseId) {
|
|
853
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
854
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
855
|
+
releaseActionService.countActions({
|
|
856
|
+
filters: {
|
|
857
|
+
release: releaseId
|
|
858
|
+
}
|
|
859
|
+
}),
|
|
860
|
+
releaseActionService.countActions({
|
|
861
|
+
filters: {
|
|
862
|
+
release: releaseId,
|
|
863
|
+
isEntryValid: false
|
|
864
|
+
}
|
|
865
|
+
})
|
|
866
|
+
]);
|
|
867
|
+
if (totalActions > 0) {
|
|
868
|
+
if (invalidActions > 0) {
|
|
869
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
870
|
+
where: {
|
|
871
|
+
id: releaseId
|
|
872
|
+
},
|
|
873
|
+
data: {
|
|
874
|
+
status: "blocked"
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
879
|
+
where: {
|
|
880
|
+
id: releaseId
|
|
881
|
+
},
|
|
882
|
+
data: {
|
|
883
|
+
status: "ready"
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
888
|
+
where: {
|
|
889
|
+
id: releaseId
|
|
890
|
+
},
|
|
891
|
+
data: {
|
|
892
|
+
status: "empty"
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
};
|
|
898
|
+
const getGroupName = (queryValue) => {
|
|
899
|
+
switch (queryValue) {
|
|
900
|
+
case "contentType":
|
|
901
|
+
return "contentType.displayName";
|
|
902
|
+
case "type":
|
|
903
|
+
return "type";
|
|
904
|
+
case "locale":
|
|
905
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
906
|
+
default:
|
|
907
|
+
return "contentType.displayName";
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
911
|
+
const getLocalesDataForActions = async () => {
|
|
912
|
+
if (!strapi2.plugin("i18n")) {
|
|
913
|
+
return {};
|
|
914
|
+
}
|
|
915
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
916
|
+
return allLocales.reduce((acc, locale) => {
|
|
917
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
918
|
+
return acc;
|
|
919
|
+
}, {});
|
|
920
|
+
};
|
|
921
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
922
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
923
|
+
const contentTypesData = {};
|
|
924
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
925
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
926
|
+
uid: contentTypeUid
|
|
927
|
+
});
|
|
928
|
+
contentTypesData[contentTypeUid] = {
|
|
929
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
930
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
return contentTypesData;
|
|
934
|
+
};
|
|
935
|
+
return {
|
|
936
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
937
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
708
938
|
strapi: strapi2
|
|
709
939
|
});
|
|
710
940
|
await Promise.all([
|
|
711
|
-
|
|
941
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
712
942
|
validateUniqueEntry(releaseId, action)
|
|
713
943
|
]);
|
|
714
|
-
const
|
|
944
|
+
const model = strapi2.contentType(action.contentType);
|
|
945
|
+
if (model.kind === "singleType") {
|
|
946
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
947
|
+
if (!document) {
|
|
948
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
949
|
+
}
|
|
950
|
+
action.entryDocumentId = document.documentId;
|
|
951
|
+
}
|
|
952
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
715
953
|
if (!release2) {
|
|
716
954
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
717
955
|
}
|
|
718
956
|
if (release2.releasedAt) {
|
|
719
957
|
throw new utils.errors.ValidationError("Release already published");
|
|
720
958
|
}
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
959
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
960
|
+
{
|
|
961
|
+
contentType: action.contentType,
|
|
962
|
+
documentId: action.entryDocumentId,
|
|
963
|
+
locale: action.locale
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
strapi: strapi2
|
|
967
|
+
}
|
|
968
|
+
) : true;
|
|
969
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
725
970
|
data: {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
isEntryValid,
|
|
730
|
-
entry: {
|
|
731
|
-
id: entry.id,
|
|
732
|
-
__type: entry.contentType,
|
|
733
|
-
__pivot: { field: "entry" }
|
|
734
|
-
},
|
|
735
|
-
release: releaseId
|
|
971
|
+
...action,
|
|
972
|
+
release: release2.id,
|
|
973
|
+
isEntryValid: actionStatus
|
|
736
974
|
},
|
|
737
|
-
populate: { release: {
|
|
975
|
+
populate: { release: { select: ["id"] } }
|
|
738
976
|
});
|
|
739
|
-
|
|
977
|
+
if (!disableUpdateReleaseStatus) {
|
|
978
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
979
|
+
}
|
|
740
980
|
return releaseAction2;
|
|
741
981
|
},
|
|
742
|
-
async
|
|
743
|
-
const release2 = await strapi2.
|
|
744
|
-
|
|
982
|
+
async findPage(releaseId, query) {
|
|
983
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
984
|
+
where: { id: releaseId },
|
|
985
|
+
select: ["id"]
|
|
745
986
|
});
|
|
746
987
|
if (!release2) {
|
|
747
988
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
748
989
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
populate: "*"
|
|
754
|
-
}
|
|
755
|
-
},
|
|
756
|
-
filters: {
|
|
990
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
991
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
992
|
+
...dbQuery,
|
|
993
|
+
where: {
|
|
757
994
|
release: releaseId
|
|
758
995
|
}
|
|
759
996
|
});
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
997
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
998
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
999
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1000
|
+
const entry = await getEntry(
|
|
1001
|
+
{
|
|
1002
|
+
contentType: action.contentType,
|
|
1003
|
+
documentId: action.entryDocumentId,
|
|
1004
|
+
locale: action.locale,
|
|
1005
|
+
populate,
|
|
1006
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
1007
|
+
},
|
|
1008
|
+
{ strapi: strapi2 }
|
|
1009
|
+
);
|
|
1010
|
+
return {
|
|
1011
|
+
...action,
|
|
1012
|
+
entry,
|
|
1013
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1014
|
+
};
|
|
1015
|
+
});
|
|
1016
|
+
return {
|
|
1017
|
+
results: actionsWithEntry,
|
|
1018
|
+
pagination
|
|
1019
|
+
};
|
|
763
1020
|
},
|
|
764
1021
|
async groupActions(actions, groupBy) {
|
|
765
1022
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -768,10 +1025,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
768
1025
|
}
|
|
769
1026
|
return acc;
|
|
770
1027
|
}, []);
|
|
771
|
-
const allReleaseContentTypesDictionary = await
|
|
772
|
-
|
|
773
|
-
);
|
|
774
|
-
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
1028
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1029
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
775
1030
|
const formattedData = actions.map((action) => {
|
|
776
1031
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
777
1032
|
return {
|
|
@@ -787,30 +1042,6 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
787
1042
|
const groupName = getGroupName(groupBy);
|
|
788
1043
|
return ___default.default.groupBy(groupName)(formattedData);
|
|
789
1044
|
},
|
|
790
|
-
async getLocalesDataForActions() {
|
|
791
|
-
if (!strapi2.plugin("i18n")) {
|
|
792
|
-
return {};
|
|
793
|
-
}
|
|
794
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
795
|
-
return allLocales.reduce((acc, locale) => {
|
|
796
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
797
|
-
return acc;
|
|
798
|
-
}, {});
|
|
799
|
-
},
|
|
800
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
801
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
802
|
-
const contentTypesData = {};
|
|
803
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
804
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
805
|
-
uid: contentTypeUid
|
|
806
|
-
});
|
|
807
|
-
contentTypesData[contentTypeUid] = {
|
|
808
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
809
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
return contentTypesData;
|
|
813
|
-
},
|
|
814
1045
|
getContentTypeModelsFromActions(actions) {
|
|
815
1046
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
816
1047
|
if (!acc.includes(action.contentType)) {
|
|
@@ -827,191 +1058,37 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
827
1058
|
);
|
|
828
1059
|
return contentTypeModelsMap;
|
|
829
1060
|
},
|
|
830
|
-
async
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
const componentsMap = components.reduce(
|
|
834
|
-
(acc, component) => {
|
|
835
|
-
acc[component.uid] = component;
|
|
836
|
-
return acc;
|
|
837
|
-
},
|
|
838
|
-
{}
|
|
839
|
-
);
|
|
840
|
-
return componentsMap;
|
|
841
|
-
},
|
|
842
|
-
async delete(releaseId) {
|
|
843
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
844
|
-
populate: {
|
|
845
|
-
actions: {
|
|
846
|
-
fields: ["id"]
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
if (!release2) {
|
|
851
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
852
|
-
}
|
|
853
|
-
if (release2.releasedAt) {
|
|
854
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
855
|
-
}
|
|
856
|
-
await strapi2.db.transaction(async () => {
|
|
857
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
858
|
-
where: {
|
|
859
|
-
id: {
|
|
860
|
-
$in: release2.actions.map((action) => action.id)
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
});
|
|
864
|
-
await strapi2.entityService.delete(RELEASE_MODEL_UID, releaseId);
|
|
865
|
-
});
|
|
866
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling") && release2.scheduledAt) {
|
|
867
|
-
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
868
|
-
await schedulingService.cancel(release2.id);
|
|
869
|
-
}
|
|
870
|
-
strapi2.telemetry.send("didDeleteContentRelease");
|
|
871
|
-
return release2;
|
|
1061
|
+
async countActions(query) {
|
|
1062
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1063
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
872
1064
|
},
|
|
873
|
-
async
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
populate: {
|
|
882
|
-
entry: {
|
|
883
|
-
fields: ["id"]
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
);
|
|
890
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
891
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
892
|
-
}
|
|
893
|
-
if (releaseWithPopulatedActionEntries.releasedAt) {
|
|
894
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
895
|
-
}
|
|
896
|
-
if (releaseWithPopulatedActionEntries.actions.length === 0) {
|
|
897
|
-
throw new utils.errors.ValidationError("No entries to publish");
|
|
898
|
-
}
|
|
899
|
-
const collectionTypeActions = {};
|
|
900
|
-
const singleTypeActions = [];
|
|
901
|
-
for (const action of releaseWithPopulatedActionEntries.actions) {
|
|
902
|
-
const contentTypeUid = action.contentType;
|
|
903
|
-
if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
|
|
904
|
-
if (!collectionTypeActions[contentTypeUid]) {
|
|
905
|
-
collectionTypeActions[contentTypeUid] = {
|
|
906
|
-
entriestoPublishIds: [],
|
|
907
|
-
entriesToUnpublishIds: []
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
if (action.type === "publish") {
|
|
911
|
-
collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
|
|
912
|
-
} else {
|
|
913
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
914
|
-
}
|
|
915
|
-
} else {
|
|
916
|
-
singleTypeActions.push({
|
|
917
|
-
uid: contentTypeUid,
|
|
918
|
-
action: action.type,
|
|
919
|
-
id: action.entry.id
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
924
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
925
|
-
await strapi2.db.transaction(async () => {
|
|
926
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
927
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
928
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
929
|
-
try {
|
|
930
|
-
if (action === "publish") {
|
|
931
|
-
await entityManagerService.publish(entry, uid);
|
|
932
|
-
} else {
|
|
933
|
-
await entityManagerService.unpublish(entry, uid);
|
|
934
|
-
}
|
|
935
|
-
} catch (error) {
|
|
936
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
937
|
-
} else {
|
|
938
|
-
throw error;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
943
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
944
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
945
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
946
|
-
contentTypeUid,
|
|
947
|
-
{
|
|
948
|
-
filters: {
|
|
949
|
-
id: {
|
|
950
|
-
$in: entriestoPublishIds
|
|
951
|
-
}
|
|
952
|
-
},
|
|
953
|
-
populate
|
|
954
|
-
}
|
|
955
|
-
);
|
|
956
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
957
|
-
contentTypeUid,
|
|
958
|
-
{
|
|
959
|
-
filters: {
|
|
960
|
-
id: {
|
|
961
|
-
$in: entriesToUnpublishIds
|
|
962
|
-
}
|
|
963
|
-
},
|
|
964
|
-
populate
|
|
965
|
-
}
|
|
966
|
-
);
|
|
967
|
-
if (entriesToPublish.length > 0) {
|
|
968
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
969
|
-
}
|
|
970
|
-
if (entriesToUnpublish.length > 0) {
|
|
971
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, contentTypeUid);
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
});
|
|
975
|
-
const release2 = await strapi2.entityService.update(RELEASE_MODEL_UID, releaseId, {
|
|
976
|
-
data: {
|
|
977
|
-
/*
|
|
978
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">> looks like it's wrong
|
|
979
|
-
*/
|
|
980
|
-
// @ts-expect-error see above
|
|
981
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
982
|
-
},
|
|
983
|
-
populate: {
|
|
984
|
-
actions: {
|
|
985
|
-
// @ts-expect-error is not expecting count but it is working
|
|
986
|
-
count: true
|
|
1065
|
+
async update(actionId, releaseId, update) {
|
|
1066
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1067
|
+
where: {
|
|
1068
|
+
id: actionId,
|
|
1069
|
+
release: {
|
|
1070
|
+
id: releaseId,
|
|
1071
|
+
releasedAt: {
|
|
1072
|
+
$null: true
|
|
987
1073
|
}
|
|
988
1074
|
}
|
|
989
|
-
});
|
|
990
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
991
|
-
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
992
|
-
isPublished: true,
|
|
993
|
-
release: release2
|
|
994
|
-
});
|
|
995
1075
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
isPublished: false,
|
|
1002
|
-
error
|
|
1003
|
-
});
|
|
1004
|
-
}
|
|
1005
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1006
|
-
where: { id: releaseId },
|
|
1007
|
-
data: {
|
|
1008
|
-
status: "failed"
|
|
1009
|
-
}
|
|
1010
|
-
});
|
|
1011
|
-
throw error;
|
|
1076
|
+
});
|
|
1077
|
+
if (!action) {
|
|
1078
|
+
throw new utils.errors.NotFoundError(
|
|
1079
|
+
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1080
|
+
);
|
|
1012
1081
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1082
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1083
|
+
{
|
|
1084
|
+
contentType: action.contentType,
|
|
1085
|
+
documentId: action.entryDocumentId,
|
|
1086
|
+
locale: action.locale
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
strapi: strapi2
|
|
1090
|
+
}
|
|
1091
|
+
) : true;
|
|
1015
1092
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1016
1093
|
where: {
|
|
1017
1094
|
id: actionId,
|
|
@@ -1022,16 +1099,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1022
1099
|
}
|
|
1023
1100
|
}
|
|
1024
1101
|
},
|
|
1025
|
-
data:
|
|
1102
|
+
data: {
|
|
1103
|
+
...update,
|
|
1104
|
+
isEntryValid: actionStatus
|
|
1105
|
+
}
|
|
1026
1106
|
});
|
|
1027
|
-
|
|
1028
|
-
throw new utils.errors.NotFoundError(
|
|
1029
|
-
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1030
|
-
);
|
|
1031
|
-
}
|
|
1107
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1032
1108
|
return updatedAction;
|
|
1033
1109
|
},
|
|
1034
|
-
async
|
|
1110
|
+
async delete(actionId, releaseId) {
|
|
1035
1111
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1036
1112
|
where: {
|
|
1037
1113
|
id: actionId,
|
|
@@ -1048,87 +1124,56 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1048
1124
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1049
1125
|
);
|
|
1050
1126
|
}
|
|
1051
|
-
|
|
1127
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1052
1128
|
return deletedAction;
|
|
1053
|
-
},
|
|
1054
|
-
async updateReleaseStatus(releaseId) {
|
|
1055
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
1056
|
-
this.countActions({
|
|
1057
|
-
filters: {
|
|
1058
|
-
release: releaseId
|
|
1059
|
-
}
|
|
1060
|
-
}),
|
|
1061
|
-
this.countActions({
|
|
1062
|
-
filters: {
|
|
1063
|
-
release: releaseId,
|
|
1064
|
-
isEntryValid: false
|
|
1065
|
-
}
|
|
1066
|
-
})
|
|
1067
|
-
]);
|
|
1068
|
-
if (totalActions > 0) {
|
|
1069
|
-
if (invalidActions > 0) {
|
|
1070
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1071
|
-
where: {
|
|
1072
|
-
id: releaseId
|
|
1073
|
-
},
|
|
1074
|
-
data: {
|
|
1075
|
-
status: "blocked"
|
|
1076
|
-
}
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1080
|
-
where: {
|
|
1081
|
-
id: releaseId
|
|
1082
|
-
},
|
|
1083
|
-
data: {
|
|
1084
|
-
status: "ready"
|
|
1085
|
-
}
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1089
|
-
where: {
|
|
1090
|
-
id: releaseId
|
|
1091
|
-
},
|
|
1092
|
-
data: {
|
|
1093
|
-
status: "empty"
|
|
1094
|
-
}
|
|
1095
|
-
});
|
|
1096
1129
|
}
|
|
1097
1130
|
};
|
|
1098
1131
|
};
|
|
1132
|
+
class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
1133
|
+
constructor(message) {
|
|
1134
|
+
super(message);
|
|
1135
|
+
this.name = "AlreadyOnReleaseError";
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1099
1138
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1100
1139
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1101
|
-
const release2 = await strapi2.
|
|
1102
|
-
|
|
1140
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1141
|
+
where: {
|
|
1142
|
+
id: releaseId
|
|
1143
|
+
},
|
|
1144
|
+
populate: {
|
|
1145
|
+
actions: true
|
|
1146
|
+
}
|
|
1103
1147
|
});
|
|
1104
1148
|
if (!release2) {
|
|
1105
1149
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1106
1150
|
}
|
|
1107
1151
|
const isEntryInRelease = release2.actions.some(
|
|
1108
|
-
(action) =>
|
|
1152
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1109
1153
|
);
|
|
1110
1154
|
if (isEntryInRelease) {
|
|
1111
|
-
throw new
|
|
1112
|
-
`Entry with
|
|
1155
|
+
throw new AlreadyOnReleaseError(
|
|
1156
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1113
1157
|
);
|
|
1114
1158
|
}
|
|
1115
1159
|
},
|
|
1116
|
-
|
|
1160
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1117
1161
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1118
1162
|
if (!contentType) {
|
|
1119
1163
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1120
1164
|
}
|
|
1121
|
-
if (!contentType
|
|
1165
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1122
1166
|
throw new utils.errors.ValidationError(
|
|
1123
1167
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1124
1168
|
);
|
|
1125
1169
|
}
|
|
1170
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1171
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1172
|
+
}
|
|
1126
1173
|
},
|
|
1127
1174
|
async validatePendingReleasesLimit() {
|
|
1128
|
-
const
|
|
1129
|
-
|
|
1130
|
-
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1131
|
-
);
|
|
1175
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1176
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1132
1177
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1133
1178
|
filters: {
|
|
1134
1179
|
releasedAt: {
|
|
@@ -1141,8 +1186,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1141
1186
|
}
|
|
1142
1187
|
},
|
|
1143
1188
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1144
|
-
const pendingReleases = await strapi2.
|
|
1145
|
-
|
|
1189
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1190
|
+
where: {
|
|
1146
1191
|
releasedAt: {
|
|
1147
1192
|
$null: true
|
|
1148
1193
|
},
|
|
@@ -1171,7 +1216,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1171
1216
|
}
|
|
1172
1217
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1173
1218
|
try {
|
|
1174
|
-
await getService("release").publish(releaseId);
|
|
1219
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1175
1220
|
} catch (error) {
|
|
1176
1221
|
}
|
|
1177
1222
|
this.cancel(releaseId);
|
|
@@ -1213,85 +1258,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1213
1258
|
}
|
|
1214
1259
|
};
|
|
1215
1260
|
};
|
|
1261
|
+
const DEFAULT_SETTINGS = {
|
|
1262
|
+
defaultTimezone: null
|
|
1263
|
+
};
|
|
1264
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1265
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1266
|
+
return {
|
|
1267
|
+
async update({ settings: settings2 }) {
|
|
1268
|
+
const store = await getStore();
|
|
1269
|
+
store.set({ key: "settings", value: settings2 });
|
|
1270
|
+
return settings2;
|
|
1271
|
+
},
|
|
1272
|
+
async find() {
|
|
1273
|
+
const store = await getStore();
|
|
1274
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1275
|
+
return {
|
|
1276
|
+
...DEFAULT_SETTINGS,
|
|
1277
|
+
...settings2 || {}
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
};
|
|
1216
1282
|
const services = {
|
|
1217
1283
|
release: createReleaseService,
|
|
1284
|
+
"release-action": createReleaseActionService,
|
|
1218
1285
|
"release-validation": createReleaseValidationService,
|
|
1219
|
-
|
|
1286
|
+
scheduling: createSchedulingService,
|
|
1287
|
+
settings: createSettingsService
|
|
1220
1288
|
};
|
|
1221
|
-
const RELEASE_SCHEMA =
|
|
1222
|
-
name:
|
|
1223
|
-
scheduledAt:
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
otherwise: yup__namespace.string().nullable()
|
|
1229
|
-
}),
|
|
1230
|
-
timezone: yup__namespace.string().when("isScheduled", {
|
|
1231
|
-
is: true,
|
|
1232
|
-
then: yup__namespace.string().required().nullable(),
|
|
1233
|
-
otherwise: yup__namespace.string().nullable()
|
|
1234
|
-
}),
|
|
1235
|
-
date: yup__namespace.string().when("isScheduled", {
|
|
1236
|
-
is: true,
|
|
1237
|
-
then: yup__namespace.string().required().nullable(),
|
|
1238
|
-
otherwise: yup__namespace.string().nullable()
|
|
1289
|
+
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1290
|
+
name: utils.yup.string().trim().required(),
|
|
1291
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1292
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1293
|
+
is: (value) => value !== null && value !== void 0,
|
|
1294
|
+
then: utils.yup.string().required(),
|
|
1295
|
+
otherwise: utils.yup.string().nullable()
|
|
1239
1296
|
})
|
|
1240
1297
|
}).required().noUnknown();
|
|
1298
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1299
|
+
contentType: utils.yup.string().required(),
|
|
1300
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1301
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1302
|
+
locale: utils.yup.string().nullable()
|
|
1303
|
+
}).required().noUnknown();
|
|
1241
1304
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1305
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1306
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1307
|
+
);
|
|
1242
1308
|
const releaseController = {
|
|
1243
|
-
|
|
1244
|
-
|
|
1309
|
+
/**
|
|
1310
|
+
* Find releases based on documents attached or not to the release.
|
|
1311
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1312
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1313
|
+
*/
|
|
1314
|
+
async findByDocumentAttached(ctx) {
|
|
1315
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1245
1316
|
ability: ctx.state.userAbility,
|
|
1246
1317
|
model: RELEASE_MODEL_UID
|
|
1247
1318
|
});
|
|
1248
1319
|
await permissionsManager.validateQuery(ctx.query);
|
|
1249
1320
|
const releaseService = getService("release", { strapi });
|
|
1250
|
-
const
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1321
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1322
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1323
|
+
const model = strapi.getModel(query.contentType);
|
|
1324
|
+
if (model.kind && model.kind === "singleType") {
|
|
1325
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1326
|
+
if (!document) {
|
|
1327
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1328
|
+
}
|
|
1329
|
+
query.entryDocumentId = document.documentId;
|
|
1330
|
+
}
|
|
1331
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1332
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1333
|
+
if (isEntryAttached) {
|
|
1334
|
+
const releases = await releaseService.findMany({
|
|
1335
|
+
where: {
|
|
1336
|
+
releasedAt: null,
|
|
1265
1337
|
actions: {
|
|
1266
|
-
|
|
1267
|
-
|
|
1338
|
+
contentType,
|
|
1339
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1340
|
+
locale: locale ?? null
|
|
1341
|
+
}
|
|
1342
|
+
},
|
|
1343
|
+
populate: {
|
|
1344
|
+
actions: {
|
|
1345
|
+
fields: ["type"],
|
|
1346
|
+
filters: {
|
|
1347
|
+
contentType,
|
|
1348
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1349
|
+
locale: locale ?? null
|
|
1268
1350
|
}
|
|
1269
1351
|
}
|
|
1270
|
-
}
|
|
1352
|
+
}
|
|
1353
|
+
});
|
|
1354
|
+
ctx.body = { data: releases };
|
|
1355
|
+
} else {
|
|
1356
|
+
const relatedReleases = await releaseService.findMany({
|
|
1357
|
+
where: {
|
|
1358
|
+
releasedAt: null,
|
|
1359
|
+
actions: {
|
|
1360
|
+
contentType,
|
|
1361
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1362
|
+
locale: locale ?? null
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1271
1365
|
});
|
|
1272
|
-
const
|
|
1366
|
+
const releases = await releaseService.findMany({
|
|
1273
1367
|
where: {
|
|
1368
|
+
$or: [
|
|
1369
|
+
{
|
|
1370
|
+
id: {
|
|
1371
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1372
|
+
}
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
actions: null
|
|
1376
|
+
}
|
|
1377
|
+
],
|
|
1274
1378
|
releasedAt: null
|
|
1275
1379
|
}
|
|
1276
1380
|
});
|
|
1277
|
-
ctx.body = { data
|
|
1381
|
+
ctx.body = { data: releases };
|
|
1278
1382
|
}
|
|
1279
1383
|
},
|
|
1384
|
+
async findPage(ctx) {
|
|
1385
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1386
|
+
ability: ctx.state.userAbility,
|
|
1387
|
+
model: RELEASE_MODEL_UID
|
|
1388
|
+
});
|
|
1389
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1390
|
+
const releaseService = getService("release", { strapi });
|
|
1391
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1392
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1393
|
+
const data = results.map((release2) => {
|
|
1394
|
+
const { actions, ...releaseData } = release2;
|
|
1395
|
+
return {
|
|
1396
|
+
...releaseData,
|
|
1397
|
+
actions: {
|
|
1398
|
+
meta: {
|
|
1399
|
+
count: actions.count
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
});
|
|
1404
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1405
|
+
where: {
|
|
1406
|
+
releasedAt: null
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1410
|
+
},
|
|
1280
1411
|
async findOne(ctx) {
|
|
1281
1412
|
const id = ctx.params.id;
|
|
1282
1413
|
const releaseService = getService("release", { strapi });
|
|
1414
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1283
1415
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1284
1416
|
if (!release2) {
|
|
1285
1417
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1286
1418
|
}
|
|
1287
|
-
const count = await
|
|
1419
|
+
const count = await releaseActionService.countActions({
|
|
1288
1420
|
filters: {
|
|
1289
1421
|
release: id
|
|
1290
1422
|
}
|
|
1291
1423
|
});
|
|
1292
1424
|
const sanitizedRelease = {
|
|
1293
1425
|
...release2,
|
|
1294
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1426
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1295
1427
|
};
|
|
1296
1428
|
const data = {
|
|
1297
1429
|
...sanitizedRelease,
|
|
@@ -1303,19 +1435,63 @@ const releaseController = {
|
|
|
1303
1435
|
};
|
|
1304
1436
|
ctx.body = { data };
|
|
1305
1437
|
},
|
|
1438
|
+
async mapEntriesToReleases(ctx) {
|
|
1439
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1440
|
+
if (!contentTypeUid || !documentIds) {
|
|
1441
|
+
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1442
|
+
}
|
|
1443
|
+
const releaseService = getService("release", { strapi });
|
|
1444
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1445
|
+
where: {
|
|
1446
|
+
releasedAt: null,
|
|
1447
|
+
actions: {
|
|
1448
|
+
contentType: contentTypeUid,
|
|
1449
|
+
entryDocumentId: {
|
|
1450
|
+
$in: documentIds
|
|
1451
|
+
},
|
|
1452
|
+
locale
|
|
1453
|
+
}
|
|
1454
|
+
},
|
|
1455
|
+
populate: {
|
|
1456
|
+
actions: true
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1460
|
+
(acc, release2) => {
|
|
1461
|
+
release2.actions.forEach((action) => {
|
|
1462
|
+
if (action.contentType !== contentTypeUid) {
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
if (locale && action.locale !== locale) {
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
if (!acc[action.entryDocumentId]) {
|
|
1469
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1470
|
+
} else {
|
|
1471
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
return acc;
|
|
1475
|
+
},
|
|
1476
|
+
{}
|
|
1477
|
+
);
|
|
1478
|
+
ctx.body = {
|
|
1479
|
+
data: mappedEntriesInReleases
|
|
1480
|
+
};
|
|
1481
|
+
},
|
|
1306
1482
|
async create(ctx) {
|
|
1307
1483
|
const user = ctx.state.user;
|
|
1308
1484
|
const releaseArgs = ctx.request.body;
|
|
1309
1485
|
await validateRelease(releaseArgs);
|
|
1310
1486
|
const releaseService = getService("release", { strapi });
|
|
1311
1487
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1312
|
-
const permissionsManager = strapi.admin
|
|
1488
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1313
1489
|
ability: ctx.state.userAbility,
|
|
1314
1490
|
model: RELEASE_MODEL_UID
|
|
1315
1491
|
});
|
|
1316
|
-
ctx.
|
|
1492
|
+
ctx.created({
|
|
1317
1493
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1318
|
-
};
|
|
1494
|
+
});
|
|
1319
1495
|
},
|
|
1320
1496
|
async update(ctx) {
|
|
1321
1497
|
const user = ctx.state.user;
|
|
@@ -1324,7 +1500,7 @@ const releaseController = {
|
|
|
1324
1500
|
await validateRelease(releaseArgs);
|
|
1325
1501
|
const releaseService = getService("release", { strapi });
|
|
1326
1502
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1327
|
-
const permissionsManager = strapi.admin
|
|
1503
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1328
1504
|
ability: ctx.state.userAbility,
|
|
1329
1505
|
model: RELEASE_MODEL_UID
|
|
1330
1506
|
});
|
|
@@ -1341,18 +1517,18 @@ const releaseController = {
|
|
|
1341
1517
|
};
|
|
1342
1518
|
},
|
|
1343
1519
|
async publish(ctx) {
|
|
1344
|
-
const user = ctx.state.user;
|
|
1345
1520
|
const id = ctx.params.id;
|
|
1346
1521
|
const releaseService = getService("release", { strapi });
|
|
1347
|
-
const
|
|
1522
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1523
|
+
const release2 = await releaseService.publish(id);
|
|
1348
1524
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1349
|
-
|
|
1525
|
+
releaseActionService.countActions({
|
|
1350
1526
|
filters: {
|
|
1351
1527
|
release: id,
|
|
1352
1528
|
type: "publish"
|
|
1353
1529
|
}
|
|
1354
1530
|
}),
|
|
1355
|
-
|
|
1531
|
+
releaseActionService.countActions({
|
|
1356
1532
|
filters: {
|
|
1357
1533
|
release: id,
|
|
1358
1534
|
type: "unpublish"
|
|
@@ -1370,57 +1546,106 @@ const releaseController = {
|
|
|
1370
1546
|
}
|
|
1371
1547
|
};
|
|
1372
1548
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
}).required(),
|
|
1549
|
+
contentType: utils.yup.string().required(),
|
|
1550
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1551
|
+
locale: utils.yup.string(),
|
|
1377
1552
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1378
1553
|
});
|
|
1379
1554
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1380
1555
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1381
1556
|
});
|
|
1557
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1558
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1559
|
+
});
|
|
1382
1560
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1383
1561
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1562
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1384
1563
|
const releaseActionController = {
|
|
1385
1564
|
async create(ctx) {
|
|
1386
1565
|
const releaseId = ctx.params.releaseId;
|
|
1387
1566
|
const releaseActionArgs = ctx.request.body;
|
|
1388
1567
|
await validateReleaseAction(releaseActionArgs);
|
|
1389
|
-
const
|
|
1390
|
-
const releaseAction2 = await
|
|
1391
|
-
ctx.
|
|
1568
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1569
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1570
|
+
ctx.created({
|
|
1392
1571
|
data: releaseAction2
|
|
1393
|
-
};
|
|
1572
|
+
});
|
|
1573
|
+
},
|
|
1574
|
+
async createMany(ctx) {
|
|
1575
|
+
const releaseId = ctx.params.releaseId;
|
|
1576
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1577
|
+
await Promise.all(
|
|
1578
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1579
|
+
);
|
|
1580
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1581
|
+
const releaseService = getService("release", { strapi });
|
|
1582
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1583
|
+
const releaseActions2 = await Promise.all(
|
|
1584
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1585
|
+
try {
|
|
1586
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1587
|
+
disableUpdateReleaseStatus: true
|
|
1588
|
+
});
|
|
1589
|
+
return action;
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1592
|
+
return null;
|
|
1593
|
+
}
|
|
1594
|
+
throw error;
|
|
1595
|
+
}
|
|
1596
|
+
})
|
|
1597
|
+
);
|
|
1598
|
+
return releaseActions2;
|
|
1599
|
+
});
|
|
1600
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1601
|
+
if (newReleaseActions.length > 0) {
|
|
1602
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1603
|
+
}
|
|
1604
|
+
ctx.created({
|
|
1605
|
+
data: newReleaseActions,
|
|
1606
|
+
meta: {
|
|
1607
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1608
|
+
totalEntries: releaseActions.length
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1394
1611
|
},
|
|
1395
1612
|
async findMany(ctx) {
|
|
1396
1613
|
const releaseId = ctx.params.releaseId;
|
|
1397
|
-
const permissionsManager = strapi.admin
|
|
1614
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1398
1615
|
ability: ctx.state.userAbility,
|
|
1399
1616
|
model: RELEASE_ACTION_MODEL_UID
|
|
1400
1617
|
});
|
|
1618
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1619
|
+
if (ctx.query.groupBy) {
|
|
1620
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1621
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1625
|
+
delete ctx.query.groupBy;
|
|
1401
1626
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1402
|
-
const
|
|
1403
|
-
const { results, pagination } = await
|
|
1404
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1627
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1628
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1405
1629
|
...query
|
|
1406
1630
|
});
|
|
1407
1631
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1408
1632
|
if (acc[action.contentType]) {
|
|
1409
1633
|
return acc;
|
|
1410
1634
|
}
|
|
1411
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1635
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1412
1636
|
ability: ctx.state.userAbility,
|
|
1413
1637
|
model: action.contentType
|
|
1414
1638
|
});
|
|
1415
1639
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1416
1640
|
return acc;
|
|
1417
1641
|
}, {});
|
|
1418
|
-
const sanitizedResults = await utils.
|
|
1642
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1419
1643
|
...action,
|
|
1420
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1644
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1421
1645
|
}));
|
|
1422
|
-
const groupedData = await
|
|
1423
|
-
const contentTypes2 =
|
|
1646
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1647
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1648
|
+
const releaseService = getService("release", { strapi });
|
|
1424
1649
|
const components = await releaseService.getAllComponents();
|
|
1425
1650
|
ctx.body = {
|
|
1426
1651
|
data: groupedData,
|
|
@@ -1436,8 +1661,8 @@ const releaseActionController = {
|
|
|
1436
1661
|
const releaseId = ctx.params.releaseId;
|
|
1437
1662
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1438
1663
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1439
|
-
const
|
|
1440
|
-
const updatedAction = await
|
|
1664
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1665
|
+
const updatedAction = await releaseActionService.update(
|
|
1441
1666
|
actionId,
|
|
1442
1667
|
releaseId,
|
|
1443
1668
|
releaseActionUpdateArgs
|
|
@@ -1449,17 +1674,71 @@ const releaseActionController = {
|
|
|
1449
1674
|
async delete(ctx) {
|
|
1450
1675
|
const actionId = ctx.params.actionId;
|
|
1451
1676
|
const releaseId = ctx.params.releaseId;
|
|
1452
|
-
const
|
|
1453
|
-
const deletedReleaseAction = await
|
|
1677
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1678
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1454
1679
|
ctx.body = {
|
|
1455
1680
|
data: deletedReleaseAction
|
|
1456
1681
|
};
|
|
1457
1682
|
}
|
|
1458
1683
|
};
|
|
1459
|
-
const
|
|
1684
|
+
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1685
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1686
|
+
}).required().noUnknown();
|
|
1687
|
+
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1688
|
+
const settingsController = {
|
|
1689
|
+
async find(ctx) {
|
|
1690
|
+
const settingsService = getService("settings", { strapi });
|
|
1691
|
+
const settings2 = await settingsService.find();
|
|
1692
|
+
ctx.body = { data: settings2 };
|
|
1693
|
+
},
|
|
1694
|
+
async update(ctx) {
|
|
1695
|
+
const settingsBody = ctx.request.body;
|
|
1696
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1697
|
+
const settingsService = getService("settings", { strapi });
|
|
1698
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1699
|
+
ctx.body = { data: updatedSettings };
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
const controllers = {
|
|
1703
|
+
release: releaseController,
|
|
1704
|
+
"release-action": releaseActionController,
|
|
1705
|
+
settings: settingsController
|
|
1706
|
+
};
|
|
1460
1707
|
const release = {
|
|
1461
1708
|
type: "admin",
|
|
1462
1709
|
routes: [
|
|
1710
|
+
{
|
|
1711
|
+
method: "GET",
|
|
1712
|
+
path: "/mapEntriesToReleases",
|
|
1713
|
+
handler: "release.mapEntriesToReleases",
|
|
1714
|
+
config: {
|
|
1715
|
+
policies: [
|
|
1716
|
+
"admin::isAuthenticatedAdmin",
|
|
1717
|
+
{
|
|
1718
|
+
name: "admin::hasPermissions",
|
|
1719
|
+
config: {
|
|
1720
|
+
actions: ["plugin::content-releases.read"]
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
]
|
|
1724
|
+
}
|
|
1725
|
+
},
|
|
1726
|
+
{
|
|
1727
|
+
method: "GET",
|
|
1728
|
+
path: "/getByDocumentAttached",
|
|
1729
|
+
handler: "release.findByDocumentAttached",
|
|
1730
|
+
config: {
|
|
1731
|
+
policies: [
|
|
1732
|
+
"admin::isAuthenticatedAdmin",
|
|
1733
|
+
{
|
|
1734
|
+
name: "admin::hasPermissions",
|
|
1735
|
+
config: {
|
|
1736
|
+
actions: ["plugin::content-releases.read"]
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
]
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1463
1742
|
{
|
|
1464
1743
|
method: "POST",
|
|
1465
1744
|
path: "/",
|
|
@@ -1479,7 +1758,7 @@ const release = {
|
|
|
1479
1758
|
{
|
|
1480
1759
|
method: "GET",
|
|
1481
1760
|
path: "/",
|
|
1482
|
-
handler: "release.
|
|
1761
|
+
handler: "release.findPage",
|
|
1483
1762
|
config: {
|
|
1484
1763
|
policies: [
|
|
1485
1764
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1577,6 +1856,22 @@ const releaseAction = {
|
|
|
1577
1856
|
]
|
|
1578
1857
|
}
|
|
1579
1858
|
},
|
|
1859
|
+
{
|
|
1860
|
+
method: "POST",
|
|
1861
|
+
path: "/:releaseId/actions/bulk",
|
|
1862
|
+
handler: "release-action.createMany",
|
|
1863
|
+
config: {
|
|
1864
|
+
policies: [
|
|
1865
|
+
"admin::isAuthenticatedAdmin",
|
|
1866
|
+
{
|
|
1867
|
+
name: "admin::hasPermissions",
|
|
1868
|
+
config: {
|
|
1869
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
]
|
|
1873
|
+
}
|
|
1874
|
+
},
|
|
1580
1875
|
{
|
|
1581
1876
|
method: "GET",
|
|
1582
1877
|
path: "/:releaseId/actions",
|
|
@@ -1627,13 +1922,50 @@ const releaseAction = {
|
|
|
1627
1922
|
}
|
|
1628
1923
|
]
|
|
1629
1924
|
};
|
|
1925
|
+
const settings = {
|
|
1926
|
+
type: "admin",
|
|
1927
|
+
routes: [
|
|
1928
|
+
{
|
|
1929
|
+
method: "GET",
|
|
1930
|
+
path: "/settings",
|
|
1931
|
+
handler: "settings.find",
|
|
1932
|
+
config: {
|
|
1933
|
+
policies: [
|
|
1934
|
+
"admin::isAuthenticatedAdmin",
|
|
1935
|
+
{
|
|
1936
|
+
name: "admin::hasPermissions",
|
|
1937
|
+
config: {
|
|
1938
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
]
|
|
1942
|
+
}
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
method: "PUT",
|
|
1946
|
+
path: "/settings",
|
|
1947
|
+
handler: "settings.update",
|
|
1948
|
+
config: {
|
|
1949
|
+
policies: [
|
|
1950
|
+
"admin::isAuthenticatedAdmin",
|
|
1951
|
+
{
|
|
1952
|
+
name: "admin::hasPermissions",
|
|
1953
|
+
config: {
|
|
1954
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
]
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
]
|
|
1961
|
+
};
|
|
1630
1962
|
const routes = {
|
|
1963
|
+
settings,
|
|
1631
1964
|
release,
|
|
1632
1965
|
"release-action": releaseAction
|
|
1633
1966
|
};
|
|
1634
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1635
1967
|
const getPlugin = () => {
|
|
1636
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1968
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1637
1969
|
return {
|
|
1638
1970
|
register,
|
|
1639
1971
|
bootstrap,
|
|
@@ -1645,6 +1977,9 @@ const getPlugin = () => {
|
|
|
1645
1977
|
};
|
|
1646
1978
|
}
|
|
1647
1979
|
return {
|
|
1980
|
+
// Always return register, it handles its own feature check
|
|
1981
|
+
register,
|
|
1982
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1648
1983
|
contentTypes
|
|
1649
1984
|
};
|
|
1650
1985
|
};
|