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