@strapi/content-releases 0.0.0-next.b6d552f6e63dec5627cb8611ab2adcb8244359be → 0.0.0-next.bb6ff32f5168f3e380d3d9acba90a9d53bfcfb89
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-BX6_LcmS.mjs +1559 -0
- package/dist/_chunks/App-BX6_LcmS.mjs.map +1 -0
- package/dist/_chunks/App-DITZWWqI.js +1580 -0
- package/dist/_chunks/App-DITZWWqI.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-BMgLwqci.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-BMgLwqci.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-DZcRvN_O.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-DZcRvN_O.js.map +1 -0
- package/dist/_chunks/{en-gcJJ5htG.js → en-BWPPsSH-.js} +28 -4
- package/dist/_chunks/en-BWPPsSH-.js.map +1 -0
- package/dist/_chunks/{en-WuuhP6Bn.mjs → en-D9Q4YW03.mjs} +28 -4
- package/dist/_chunks/en-D9Q4YW03.mjs.map +1 -0
- package/dist/_chunks/index-CBsSVKTv.mjs +1380 -0
- package/dist/_chunks/index-CBsSVKTv.mjs.map +1 -0
- package/dist/_chunks/index-TfMp19WL.js +1399 -0
- package/dist/_chunks/index-TfMp19WL.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/EntryValidationPopover.d.ts +13 -0
- package/dist/admin/src/components/RelativeTime.d.ts +28 -0
- package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
- package/dist/admin/src/components/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 +1107 -662
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1108 -662
- 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 +2111 -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 +1824 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/release-action.d.ts +34 -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 +137 -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 +35 -39
- package/dist/_chunks/App-5G7GEzBM.js +0 -1317
- package/dist/_chunks/App-5G7GEzBM.js.map +0 -1
- package/dist/_chunks/App-WMxox0mk.mjs +0 -1294
- package/dist/_chunks/App-WMxox0mk.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
- package/dist/_chunks/en-WuuhP6Bn.mjs.map +0 -1
- package/dist/_chunks/en-gcJJ5htG.js.map +0 -1
- package/dist/_chunks/index-BZ8RPGiV.mjs +0 -1013
- package/dist/_chunks/index-BZ8RPGiV.mjs.map +0 -1
- package/dist/_chunks/index-pQ3hnZJy.js +0 -1034
- package/dist/_chunks/index-pQ3hnZJy.js.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),
|
|
@@ -96,11 +111,54 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
96
111
|
// @ts-expect-error - FIXME: entity here is unnecessary
|
|
97
112
|
entry
|
|
98
113
|
);
|
|
114
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
115
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
116
|
+
populate: "stageRequiredToPublish"
|
|
117
|
+
});
|
|
118
|
+
if (workflow?.stageRequiredToPublish) {
|
|
119
|
+
return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;
|
|
120
|
+
}
|
|
99
121
|
return true;
|
|
100
122
|
} catch {
|
|
101
123
|
return false;
|
|
102
124
|
}
|
|
103
125
|
};
|
|
126
|
+
const getEntry = async ({
|
|
127
|
+
contentType,
|
|
128
|
+
documentId,
|
|
129
|
+
locale,
|
|
130
|
+
populate,
|
|
131
|
+
status = "draft"
|
|
132
|
+
}, { strapi: strapi2 }) => {
|
|
133
|
+
if (documentId) {
|
|
134
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
135
|
+
if (status === "published" && !entry) {
|
|
136
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
137
|
+
}
|
|
138
|
+
return entry;
|
|
139
|
+
}
|
|
140
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
141
|
+
};
|
|
142
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
143
|
+
if (entry.publishedAt) {
|
|
144
|
+
return "published";
|
|
145
|
+
}
|
|
146
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
147
|
+
documentId: entry.documentId,
|
|
148
|
+
locale: entry.locale,
|
|
149
|
+
status: "published",
|
|
150
|
+
fields: ["updatedAt"]
|
|
151
|
+
});
|
|
152
|
+
if (!publishedEntry) {
|
|
153
|
+
return "draft";
|
|
154
|
+
}
|
|
155
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
156
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
157
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
158
|
+
return "modified";
|
|
159
|
+
}
|
|
160
|
+
return "published";
|
|
161
|
+
};
|
|
104
162
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
105
163
|
oldContentTypes,
|
|
106
164
|
contentTypes: contentTypes2
|
|
@@ -122,7 +180,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
122
180
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
123
181
|
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
124
182
|
if (deletedContentTypes.length) {
|
|
125
|
-
await utils.
|
|
183
|
+
await utils.async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
126
184
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
127
185
|
});
|
|
128
186
|
}
|
|
@@ -141,25 +199,27 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
141
199
|
}
|
|
142
200
|
}
|
|
143
201
|
});
|
|
144
|
-
utils.
|
|
202
|
+
utils.async.map(releasesWithoutStatus, async (release2) => {
|
|
145
203
|
const actions = release2.actions;
|
|
146
204
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
147
205
|
for (const action of notValidatedActions) {
|
|
148
206
|
if (action.entry) {
|
|
149
|
-
const
|
|
150
|
-
|
|
207
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
208
|
+
{
|
|
209
|
+
contentType: action.contentType,
|
|
210
|
+
documentId: action.entryDocumentId,
|
|
211
|
+
locale: action.locale
|
|
212
|
+
},
|
|
213
|
+
{ strapi }
|
|
214
|
+
);
|
|
215
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
216
|
+
where: {
|
|
217
|
+
id: action.id
|
|
218
|
+
},
|
|
219
|
+
data: {
|
|
220
|
+
isEntryValid: isEntryValid2
|
|
221
|
+
}
|
|
151
222
|
});
|
|
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
223
|
}
|
|
164
224
|
}
|
|
165
225
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -172,7 +232,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
172
232
|
}
|
|
173
233
|
}
|
|
174
234
|
});
|
|
175
|
-
utils.
|
|
235
|
+
utils.async.map(publishedReleases, async (release2) => {
|
|
176
236
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
177
237
|
where: {
|
|
178
238
|
id: release2.id
|
|
@@ -189,7 +249,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
189
249
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
190
250
|
);
|
|
191
251
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
192
|
-
utils.
|
|
252
|
+
utils.async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
193
253
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
194
254
|
const contentType = contentTypes2[contentTypeUID];
|
|
195
255
|
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -202,187 +262,272 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
202
262
|
release: true
|
|
203
263
|
}
|
|
204
264
|
});
|
|
205
|
-
await utils.
|
|
206
|
-
if (action.entry) {
|
|
207
|
-
const
|
|
208
|
-
|
|
265
|
+
await utils.async.map(actions, async (action) => {
|
|
266
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
267
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
268
|
+
{
|
|
269
|
+
contentType: contentTypeUID,
|
|
270
|
+
documentId: action.entryDocumentId,
|
|
271
|
+
locale: action.locale
|
|
272
|
+
},
|
|
273
|
+
{ strapi }
|
|
274
|
+
);
|
|
275
|
+
releasesAffected.add(action.release.id);
|
|
276
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
277
|
+
where: {
|
|
278
|
+
id: action.id
|
|
279
|
+
},
|
|
280
|
+
data: {
|
|
281
|
+
isEntryValid: isEntryValid2
|
|
282
|
+
}
|
|
209
283
|
});
|
|
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
284
|
}
|
|
225
285
|
});
|
|
226
286
|
}
|
|
227
287
|
}).then(() => {
|
|
228
|
-
utils.
|
|
288
|
+
utils.async.map(releasesAffected, async (releaseId) => {
|
|
229
289
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
230
290
|
});
|
|
231
291
|
});
|
|
232
292
|
}
|
|
233
293
|
}
|
|
234
|
-
|
|
294
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
295
|
+
if (!oldContentTypes) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
299
|
+
if (!i18nPlugin) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
for (const uid in contentTypes2) {
|
|
303
|
+
if (!oldContentTypes[uid]) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const oldContentType = oldContentTypes[uid];
|
|
307
|
+
const contentType = contentTypes2[uid];
|
|
308
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
309
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
310
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
311
|
+
locale: null
|
|
312
|
+
}).where({ contentType: uid }).execute();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
317
|
+
if (!oldContentTypes) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
321
|
+
if (!i18nPlugin) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
for (const uid in contentTypes2) {
|
|
325
|
+
if (!oldContentTypes[uid]) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const oldContentType = oldContentTypes[uid];
|
|
329
|
+
const contentType = contentTypes2[uid];
|
|
330
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
331
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
332
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
333
|
+
const defaultLocale = await getDefaultLocale();
|
|
334
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
335
|
+
locale: defaultLocale
|
|
336
|
+
}).where({ contentType: uid }).execute();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const addEntryDocumentToReleaseActions = {
|
|
341
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
342
|
+
async up(trx, db) {
|
|
343
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
344
|
+
if (!hasTable) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
348
|
+
if (hasPolymorphicColumn) {
|
|
349
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
350
|
+
"strapi_release_actions",
|
|
351
|
+
"entry_document_id"
|
|
352
|
+
);
|
|
353
|
+
if (!hasEntryDocumentIdColumn) {
|
|
354
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
355
|
+
table.string("entry_document_id");
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
359
|
+
utils.async.map(releaseActions, async (action) => {
|
|
360
|
+
const { target_type, target_id } = action;
|
|
361
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
362
|
+
if (entry) {
|
|
363
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
async down() {
|
|
369
|
+
throw new Error("not implemented");
|
|
370
|
+
}
|
|
371
|
+
};
|
|
235
372
|
const register = async ({ strapi: strapi2 }) => {
|
|
236
|
-
if (features
|
|
237
|
-
await strapi2.admin
|
|
238
|
-
strapi2.
|
|
239
|
-
strapi2.hook("strapi::content-types.
|
|
373
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
374
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
375
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
376
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
377
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
378
|
+
}
|
|
379
|
+
if (strapi2.plugin("graphql")) {
|
|
380
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
381
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
382
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
386
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
387
|
+
where: {
|
|
388
|
+
releasedAt: null,
|
|
389
|
+
actions: {
|
|
390
|
+
contentType,
|
|
391
|
+
entryDocumentId: entry.documentId,
|
|
392
|
+
locale: entry.locale
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
397
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).updateMany({
|
|
398
|
+
where: {
|
|
399
|
+
contentType,
|
|
400
|
+
entryDocumentId: entry.documentId,
|
|
401
|
+
locale: entry.locale
|
|
402
|
+
},
|
|
403
|
+
data: {
|
|
404
|
+
isEntryValid: entryStatus
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
for (const release2 of releases) {
|
|
408
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
412
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
413
|
+
where: {
|
|
414
|
+
actions: params
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
418
|
+
where: params
|
|
419
|
+
});
|
|
420
|
+
for (const release2 of releases) {
|
|
421
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
425
|
+
if (ctx.action !== "delete") {
|
|
426
|
+
return next();
|
|
427
|
+
}
|
|
428
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
429
|
+
return next();
|
|
430
|
+
}
|
|
431
|
+
const contentType = ctx.contentType.uid;
|
|
432
|
+
const { documentId, locale } = ctx.params;
|
|
433
|
+
const result = await next();
|
|
434
|
+
if (!result) {
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
try {
|
|
438
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
439
|
+
contentType,
|
|
440
|
+
entryDocumentId: documentId,
|
|
441
|
+
...locale !== "*" && { locale }
|
|
442
|
+
});
|
|
443
|
+
} catch (error) {
|
|
444
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
445
|
+
error
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return result;
|
|
449
|
+
};
|
|
450
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
451
|
+
if (ctx.action !== "update") {
|
|
452
|
+
return next();
|
|
453
|
+
}
|
|
454
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
455
|
+
return next();
|
|
456
|
+
}
|
|
457
|
+
const contentType = ctx.contentType.uid;
|
|
458
|
+
const result = await next();
|
|
459
|
+
if (!result) {
|
|
460
|
+
return result;
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
464
|
+
} catch (error) {
|
|
465
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
466
|
+
error
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
};
|
|
471
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
472
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
473
|
+
where: {
|
|
474
|
+
actions: params
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
478
|
+
where: params
|
|
479
|
+
});
|
|
480
|
+
for (const release2 of releases) {
|
|
481
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
240
482
|
}
|
|
241
483
|
};
|
|
242
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
243
484
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
244
|
-
if (features
|
|
485
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
245
486
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
246
487
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
247
488
|
);
|
|
248
489
|
strapi2.db.lifecycles.subscribe({
|
|
249
490
|
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
|
-
/**
|
|
278
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
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
491
|
/**
|
|
290
|
-
*
|
|
291
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
492
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
292
493
|
*/
|
|
293
494
|
async afterDeleteMany(event) {
|
|
294
495
|
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
|
-
}
|
|
496
|
+
const model = strapi2.getModel(event.model.uid);
|
|
497
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
498
|
+
const { where } = event.params;
|
|
499
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
500
|
+
contentType: model.uid,
|
|
501
|
+
locale: where?.locale ?? null,
|
|
502
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
317
503
|
});
|
|
318
|
-
for (const release2 of releases) {
|
|
319
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
320
|
-
}
|
|
321
504
|
}
|
|
322
505
|
} catch (error) {
|
|
323
506
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
324
507
|
error
|
|
325
508
|
});
|
|
326
509
|
}
|
|
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
510
|
}
|
|
364
511
|
});
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
512
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
513
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
514
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
515
|
+
strapi2.log.error(
|
|
516
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
517
|
+
);
|
|
518
|
+
throw err;
|
|
519
|
+
});
|
|
520
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
521
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
522
|
+
});
|
|
376
523
|
}
|
|
377
524
|
};
|
|
378
525
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
job.cancel();
|
|
385
|
-
}
|
|
526
|
+
const scheduledJobs = getService("scheduling", {
|
|
527
|
+
strapi: strapi2
|
|
528
|
+
}).getAll();
|
|
529
|
+
for (const [, job] of scheduledJobs) {
|
|
530
|
+
job.cancel();
|
|
386
531
|
}
|
|
387
532
|
};
|
|
388
533
|
const schema$1 = {
|
|
@@ -457,15 +602,13 @@ const schema = {
|
|
|
457
602
|
enum: ["publish", "unpublish"],
|
|
458
603
|
required: true
|
|
459
604
|
},
|
|
460
|
-
entry: {
|
|
461
|
-
type: "relation",
|
|
462
|
-
relation: "morphToOne",
|
|
463
|
-
configurable: false
|
|
464
|
-
},
|
|
465
605
|
contentType: {
|
|
466
606
|
type: "string",
|
|
467
607
|
required: true
|
|
468
608
|
},
|
|
609
|
+
entryDocumentId: {
|
|
610
|
+
type: "string"
|
|
611
|
+
},
|
|
469
612
|
locale: {
|
|
470
613
|
type: "string"
|
|
471
614
|
},
|
|
@@ -487,18 +630,6 @@ const contentTypes = {
|
|
|
487
630
|
release: release$1,
|
|
488
631
|
"release-action": releaseAction$1
|
|
489
632
|
};
|
|
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
633
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
503
634
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
504
635
|
strapi2.eventHub.emit(event, {
|
|
@@ -507,6 +638,33 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
507
638
|
release: release2
|
|
508
639
|
});
|
|
509
640
|
};
|
|
641
|
+
const getFormattedActions = async (releaseId) => {
|
|
642
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
643
|
+
where: {
|
|
644
|
+
release: {
|
|
645
|
+
id: releaseId
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
if (actions.length === 0) {
|
|
650
|
+
throw new utils.errors.ValidationError("No entries to publish");
|
|
651
|
+
}
|
|
652
|
+
const formattedActions = {};
|
|
653
|
+
for (const action of actions) {
|
|
654
|
+
const contentTypeUid = action.contentType;
|
|
655
|
+
if (!formattedActions[contentTypeUid]) {
|
|
656
|
+
formattedActions[contentTypeUid] = {
|
|
657
|
+
publish: [],
|
|
658
|
+
unpublish: []
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
662
|
+
documentId: action.entryDocumentId,
|
|
663
|
+
locale: action.locale
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
return formattedActions;
|
|
667
|
+
};
|
|
510
668
|
return {
|
|
511
669
|
async create(releaseData, { user }) {
|
|
512
670
|
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
@@ -520,13 +678,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
520
678
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
521
679
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
522
680
|
]);
|
|
523
|
-
const release2 = await strapi2.
|
|
681
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
524
682
|
data: {
|
|
525
683
|
...releaseWithCreatorFields,
|
|
526
684
|
status: "empty"
|
|
527
685
|
}
|
|
528
686
|
});
|
|
529
|
-
if (
|
|
687
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
530
688
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
531
689
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
532
690
|
}
|
|
@@ -534,94 +692,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
534
692
|
return release2;
|
|
535
693
|
},
|
|
536
694
|
async findOne(id, query = {}) {
|
|
537
|
-
const
|
|
538
|
-
|
|
695
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
696
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
697
|
+
...dbQuery,
|
|
698
|
+
where: { id }
|
|
539
699
|
});
|
|
540
700
|
return release2;
|
|
541
701
|
},
|
|
542
702
|
findPage(query) {
|
|
543
|
-
|
|
544
|
-
|
|
703
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
704
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
705
|
+
...dbQuery,
|
|
545
706
|
populate: {
|
|
546
707
|
actions: {
|
|
547
|
-
// @ts-expect-error Ignore missing properties
|
|
548
708
|
count: true
|
|
549
709
|
}
|
|
550
710
|
}
|
|
551
711
|
});
|
|
552
712
|
},
|
|
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;
|
|
713
|
+
findMany(query) {
|
|
714
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
715
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
716
|
+
...dbQuery
|
|
625
717
|
});
|
|
626
718
|
},
|
|
627
719
|
async update(id, releaseData, { user }) {
|
|
@@ -636,157 +728,27 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
636
728
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
637
729
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
638
730
|
]);
|
|
639
|
-
const release2 = await strapi2.
|
|
731
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
640
732
|
if (!release2) {
|
|
641
733
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
642
734
|
}
|
|
643
735
|
if (release2.releasedAt) {
|
|
644
736
|
throw new utils.errors.ValidationError("Release already published");
|
|
645
737
|
}
|
|
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
|
|
738
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
739
|
+
where: { id },
|
|
652
740
|
data: releaseWithCreatorFields
|
|
653
741
|
});
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
schedulingService.cancel(id);
|
|
660
|
-
}
|
|
742
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
743
|
+
if (releaseData.scheduledAt) {
|
|
744
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
745
|
+
} else if (release2.scheduledAt) {
|
|
746
|
+
schedulingService.cancel(id);
|
|
661
747
|
}
|
|
662
748
|
this.updateReleaseStatus(id);
|
|
663
749
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
664
750
|
return updatedRelease;
|
|
665
751
|
},
|
|
666
|
-
async createAction(releaseId, action) {
|
|
667
|
-
const { validateEntryContentType, validateUniqueEntry } = getService("release-validation", {
|
|
668
|
-
strapi: strapi2
|
|
669
|
-
});
|
|
670
|
-
await Promise.all([
|
|
671
|
-
validateEntryContentType(action.entry.contentType),
|
|
672
|
-
validateUniqueEntry(releaseId, action)
|
|
673
|
-
]);
|
|
674
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
675
|
-
if (!release2) {
|
|
676
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
677
|
-
}
|
|
678
|
-
if (release2.releasedAt) {
|
|
679
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
680
|
-
}
|
|
681
|
-
const { entry, type } = action;
|
|
682
|
-
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
683
|
-
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
684
|
-
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
685
|
-
data: {
|
|
686
|
-
type,
|
|
687
|
-
contentType: entry.contentType,
|
|
688
|
-
locale: entry.locale,
|
|
689
|
-
isEntryValid,
|
|
690
|
-
entry: {
|
|
691
|
-
id: entry.id,
|
|
692
|
-
__type: entry.contentType,
|
|
693
|
-
__pivot: { field: "entry" }
|
|
694
|
-
},
|
|
695
|
-
release: releaseId
|
|
696
|
-
},
|
|
697
|
-
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
698
|
-
});
|
|
699
|
-
this.updateReleaseStatus(releaseId);
|
|
700
|
-
return releaseAction2;
|
|
701
|
-
},
|
|
702
|
-
async findActions(releaseId, query) {
|
|
703
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
704
|
-
fields: ["id"]
|
|
705
|
-
});
|
|
706
|
-
if (!release2) {
|
|
707
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
708
|
-
}
|
|
709
|
-
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
710
|
-
...query,
|
|
711
|
-
populate: {
|
|
712
|
-
entry: {
|
|
713
|
-
populate: "*"
|
|
714
|
-
}
|
|
715
|
-
},
|
|
716
|
-
filters: {
|
|
717
|
-
release: releaseId
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
},
|
|
721
|
-
async countActions(query) {
|
|
722
|
-
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
723
|
-
},
|
|
724
|
-
async groupActions(actions, groupBy) {
|
|
725
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
726
|
-
if (!acc.includes(action.contentType)) {
|
|
727
|
-
acc.push(action.contentType);
|
|
728
|
-
}
|
|
729
|
-
return acc;
|
|
730
|
-
}, []);
|
|
731
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
732
|
-
contentTypeUids
|
|
733
|
-
);
|
|
734
|
-
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
735
|
-
const formattedData = actions.map((action) => {
|
|
736
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
737
|
-
return {
|
|
738
|
-
...action,
|
|
739
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
740
|
-
contentType: {
|
|
741
|
-
displayName,
|
|
742
|
-
mainFieldValue: action.entry[mainField],
|
|
743
|
-
uid: action.contentType
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
});
|
|
747
|
-
const groupName = getGroupName(groupBy);
|
|
748
|
-
return ___default.default.groupBy(groupName)(formattedData);
|
|
749
|
-
},
|
|
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
|
-
getContentTypeModelsFromActions(actions) {
|
|
775
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
776
|
-
if (!acc.includes(action.contentType)) {
|
|
777
|
-
acc.push(action.contentType);
|
|
778
|
-
}
|
|
779
|
-
return acc;
|
|
780
|
-
}, []);
|
|
781
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
782
|
-
(acc, contentTypeUid) => {
|
|
783
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
784
|
-
return acc;
|
|
785
|
-
},
|
|
786
|
-
{}
|
|
787
|
-
);
|
|
788
|
-
return contentTypeModelsMap;
|
|
789
|
-
},
|
|
790
752
|
async getAllComponents() {
|
|
791
753
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
792
754
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -800,10 +762,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
800
762
|
return componentsMap;
|
|
801
763
|
},
|
|
802
764
|
async delete(releaseId) {
|
|
803
|
-
const release2 = await strapi2.
|
|
765
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
766
|
+
where: { id: releaseId },
|
|
804
767
|
populate: {
|
|
805
768
|
actions: {
|
|
806
|
-
|
|
769
|
+
select: ["id"]
|
|
807
770
|
}
|
|
808
771
|
}
|
|
809
772
|
});
|
|
@@ -821,9 +784,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
821
784
|
}
|
|
822
785
|
}
|
|
823
786
|
});
|
|
824
|
-
await strapi2.
|
|
787
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
788
|
+
where: {
|
|
789
|
+
id: releaseId
|
|
790
|
+
}
|
|
791
|
+
});
|
|
825
792
|
});
|
|
826
|
-
if (
|
|
793
|
+
if (release2.scheduledAt) {
|
|
827
794
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
828
795
|
await schedulingService.cancel(release2.id);
|
|
829
796
|
}
|
|
@@ -831,148 +798,294 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
831
798
|
return release2;
|
|
832
799
|
},
|
|
833
800
|
async publish(releaseId) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
actions: {
|
|
841
|
-
populate: {
|
|
842
|
-
entry: {
|
|
843
|
-
fields: ["id"]
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
);
|
|
850
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
801
|
+
const {
|
|
802
|
+
release: release2,
|
|
803
|
+
error
|
|
804
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
805
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
806
|
+
if (!lockedRelease) {
|
|
851
807
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
852
808
|
}
|
|
853
|
-
if (
|
|
809
|
+
if (lockedRelease.releasedAt) {
|
|
854
810
|
throw new utils.errors.ValidationError("Release already published");
|
|
855
811
|
}
|
|
856
|
-
if (
|
|
857
|
-
throw new utils.errors.ValidationError("
|
|
812
|
+
if (lockedRelease.status === "failed") {
|
|
813
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
858
814
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
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
|
|
815
|
+
try {
|
|
816
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
817
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
818
|
+
await strapi2.db.transaction(
|
|
819
|
+
async () => Promise.all(
|
|
820
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
821
|
+
const contentType = contentTypeUid;
|
|
822
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
823
|
+
return Promise.all([
|
|
824
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
825
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
826
|
+
]);
|
|
827
|
+
})
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
831
|
+
where: {
|
|
832
|
+
id: releaseId
|
|
833
|
+
},
|
|
834
|
+
data: {
|
|
835
|
+
status: "done",
|
|
836
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
947
837
|
}
|
|
948
|
-
}
|
|
949
|
-
});
|
|
950
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
838
|
+
});
|
|
951
839
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
952
840
|
isPublished: true,
|
|
953
|
-
release:
|
|
841
|
+
release: release22
|
|
954
842
|
});
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
} catch (error) {
|
|
959
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
843
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
844
|
+
return { release: release22, error: null };
|
|
845
|
+
} catch (error2) {
|
|
960
846
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
961
847
|
isPublished: false,
|
|
962
|
-
error
|
|
848
|
+
error: error2
|
|
849
|
+
});
|
|
850
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
851
|
+
status: "failed"
|
|
852
|
+
}).transacting(trx).execute();
|
|
853
|
+
return {
|
|
854
|
+
release: null,
|
|
855
|
+
error: error2
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
if (error instanceof Error) {
|
|
860
|
+
throw error;
|
|
861
|
+
}
|
|
862
|
+
return release2;
|
|
863
|
+
},
|
|
864
|
+
async updateReleaseStatus(releaseId) {
|
|
865
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
866
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
867
|
+
releaseActionService.countActions({
|
|
868
|
+
filters: {
|
|
869
|
+
release: releaseId
|
|
870
|
+
}
|
|
871
|
+
}),
|
|
872
|
+
releaseActionService.countActions({
|
|
873
|
+
filters: {
|
|
874
|
+
release: releaseId,
|
|
875
|
+
isEntryValid: false
|
|
876
|
+
}
|
|
877
|
+
})
|
|
878
|
+
]);
|
|
879
|
+
if (totalActions > 0) {
|
|
880
|
+
if (invalidActions > 0) {
|
|
881
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
882
|
+
where: {
|
|
883
|
+
id: releaseId
|
|
884
|
+
},
|
|
885
|
+
data: {
|
|
886
|
+
status: "blocked"
|
|
887
|
+
}
|
|
963
888
|
});
|
|
964
889
|
}
|
|
965
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
966
|
-
where: {
|
|
890
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
891
|
+
where: {
|
|
892
|
+
id: releaseId
|
|
893
|
+
},
|
|
967
894
|
data: {
|
|
968
|
-
status: "
|
|
895
|
+
status: "ready"
|
|
969
896
|
}
|
|
970
897
|
});
|
|
971
|
-
throw error;
|
|
972
898
|
}
|
|
899
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
900
|
+
where: {
|
|
901
|
+
id: releaseId
|
|
902
|
+
},
|
|
903
|
+
data: {
|
|
904
|
+
status: "empty"
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
};
|
|
910
|
+
const getGroupName = (queryValue) => {
|
|
911
|
+
switch (queryValue) {
|
|
912
|
+
case "contentType":
|
|
913
|
+
return "contentType.displayName";
|
|
914
|
+
case "type":
|
|
915
|
+
return "type";
|
|
916
|
+
case "locale":
|
|
917
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
918
|
+
default:
|
|
919
|
+
return "contentType.displayName";
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
923
|
+
const getLocalesDataForActions = async () => {
|
|
924
|
+
if (!strapi2.plugin("i18n")) {
|
|
925
|
+
return {};
|
|
926
|
+
}
|
|
927
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
928
|
+
return allLocales.reduce((acc, locale) => {
|
|
929
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
930
|
+
return acc;
|
|
931
|
+
}, {});
|
|
932
|
+
};
|
|
933
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
934
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
935
|
+
const contentTypesData = {};
|
|
936
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
937
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
938
|
+
uid: contentTypeUid
|
|
939
|
+
});
|
|
940
|
+
contentTypesData[contentTypeUid] = {
|
|
941
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
942
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
return contentTypesData;
|
|
946
|
+
};
|
|
947
|
+
return {
|
|
948
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
949
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
950
|
+
strapi: strapi2
|
|
951
|
+
});
|
|
952
|
+
await Promise.all([
|
|
953
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
954
|
+
validateUniqueEntry(releaseId, action)
|
|
955
|
+
]);
|
|
956
|
+
const model = strapi2.contentType(action.contentType);
|
|
957
|
+
if (model.kind === "singleType") {
|
|
958
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
959
|
+
if (!document) {
|
|
960
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
961
|
+
}
|
|
962
|
+
action.entryDocumentId = document.documentId;
|
|
963
|
+
}
|
|
964
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
965
|
+
if (!release2) {
|
|
966
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
967
|
+
}
|
|
968
|
+
if (release2.releasedAt) {
|
|
969
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
970
|
+
}
|
|
971
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
972
|
+
{
|
|
973
|
+
contentType: action.contentType,
|
|
974
|
+
documentId: action.entryDocumentId,
|
|
975
|
+
locale: action.locale
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
strapi: strapi2
|
|
979
|
+
}
|
|
980
|
+
) : true;
|
|
981
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
982
|
+
data: {
|
|
983
|
+
...action,
|
|
984
|
+
release: release2.id,
|
|
985
|
+
isEntryValid: actionStatus
|
|
986
|
+
},
|
|
987
|
+
populate: { release: { select: ["id"] } }
|
|
988
|
+
});
|
|
989
|
+
if (!disableUpdateReleaseStatus) {
|
|
990
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
991
|
+
}
|
|
992
|
+
return releaseAction2;
|
|
993
|
+
},
|
|
994
|
+
async findPage(releaseId, query) {
|
|
995
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
996
|
+
where: { id: releaseId },
|
|
997
|
+
select: ["id"]
|
|
998
|
+
});
|
|
999
|
+
if (!release2) {
|
|
1000
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1001
|
+
}
|
|
1002
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1003
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
1004
|
+
...dbQuery,
|
|
1005
|
+
where: {
|
|
1006
|
+
release: releaseId
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
1010
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
1011
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1012
|
+
const entry = await getEntry(
|
|
1013
|
+
{
|
|
1014
|
+
contentType: action.contentType,
|
|
1015
|
+
documentId: action.entryDocumentId,
|
|
1016
|
+
locale: action.locale,
|
|
1017
|
+
populate,
|
|
1018
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
1019
|
+
},
|
|
1020
|
+
{ strapi: strapi2 }
|
|
1021
|
+
);
|
|
1022
|
+
return {
|
|
1023
|
+
...action,
|
|
1024
|
+
entry,
|
|
1025
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1026
|
+
};
|
|
1027
|
+
});
|
|
1028
|
+
return {
|
|
1029
|
+
results: actionsWithEntry,
|
|
1030
|
+
pagination
|
|
1031
|
+
};
|
|
1032
|
+
},
|
|
1033
|
+
async groupActions(actions, groupBy) {
|
|
1034
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1035
|
+
if (!acc.includes(action.contentType)) {
|
|
1036
|
+
acc.push(action.contentType);
|
|
1037
|
+
}
|
|
1038
|
+
return acc;
|
|
1039
|
+
}, []);
|
|
1040
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1041
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1042
|
+
const formattedData = actions.map((action) => {
|
|
1043
|
+
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1044
|
+
return {
|
|
1045
|
+
...action,
|
|
1046
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1047
|
+
contentType: {
|
|
1048
|
+
displayName,
|
|
1049
|
+
mainFieldValue: action.entry[mainField],
|
|
1050
|
+
uid: action.contentType
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
});
|
|
1054
|
+
const groupName = getGroupName(groupBy);
|
|
1055
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
1056
|
+
},
|
|
1057
|
+
async getContentTypeModelsFromActions(actions) {
|
|
1058
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1059
|
+
if (!acc.includes(action.contentType)) {
|
|
1060
|
+
acc.push(action.contentType);
|
|
1061
|
+
}
|
|
1062
|
+
return acc;
|
|
1063
|
+
}, []);
|
|
1064
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
1065
|
+
const contentTypeModelsMap = await utils.async.reduce(contentTypeUids)(
|
|
1066
|
+
async (accPromise, contentTypeUid) => {
|
|
1067
|
+
const acc = await accPromise;
|
|
1068
|
+
const contentTypeModel = strapi2.getModel(contentTypeUid);
|
|
1069
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
1070
|
+
populate: "stageRequiredToPublish"
|
|
1071
|
+
});
|
|
1072
|
+
acc[contentTypeUid] = {
|
|
1073
|
+
...contentTypeModel,
|
|
1074
|
+
hasReviewWorkflow: !!workflow,
|
|
1075
|
+
stageRequiredToPublish: workflow?.stageRequiredToPublish
|
|
1076
|
+
};
|
|
1077
|
+
return acc;
|
|
1078
|
+
},
|
|
1079
|
+
{}
|
|
1080
|
+
);
|
|
1081
|
+
return contentTypeModelsMap;
|
|
973
1082
|
},
|
|
974
|
-
async
|
|
975
|
-
const
|
|
1083
|
+
async countActions(query) {
|
|
1084
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1085
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1086
|
+
},
|
|
1087
|
+
async update(actionId, releaseId, update) {
|
|
1088
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
976
1089
|
where: {
|
|
977
1090
|
id: actionId,
|
|
978
1091
|
release: {
|
|
@@ -981,17 +1094,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
981
1094
|
$null: true
|
|
982
1095
|
}
|
|
983
1096
|
}
|
|
984
|
-
}
|
|
985
|
-
data: update
|
|
1097
|
+
}
|
|
986
1098
|
});
|
|
987
|
-
if (!
|
|
1099
|
+
if (!action) {
|
|
988
1100
|
throw new utils.errors.NotFoundError(
|
|
989
1101
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
990
1102
|
);
|
|
991
1103
|
}
|
|
1104
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1105
|
+
{
|
|
1106
|
+
contentType: action.contentType,
|
|
1107
|
+
documentId: action.entryDocumentId,
|
|
1108
|
+
locale: action.locale
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
strapi: strapi2
|
|
1112
|
+
}
|
|
1113
|
+
) : true;
|
|
1114
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1115
|
+
where: {
|
|
1116
|
+
id: actionId,
|
|
1117
|
+
release: {
|
|
1118
|
+
id: releaseId,
|
|
1119
|
+
releasedAt: {
|
|
1120
|
+
$null: true
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
1124
|
+
data: {
|
|
1125
|
+
...update,
|
|
1126
|
+
isEntryValid: actionStatus
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
992
1130
|
return updatedAction;
|
|
993
1131
|
},
|
|
994
|
-
async
|
|
1132
|
+
async delete(actionId, releaseId) {
|
|
995
1133
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
996
1134
|
where: {
|
|
997
1135
|
id: actionId,
|
|
@@ -1008,87 +1146,104 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1008
1146
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1009
1147
|
);
|
|
1010
1148
|
}
|
|
1011
|
-
|
|
1149
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1012
1150
|
return deletedAction;
|
|
1013
1151
|
},
|
|
1014
|
-
async
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
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"
|
|
1152
|
+
async validateActionsByContentTypes(contentTypeUids) {
|
|
1153
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
1154
|
+
where: {
|
|
1155
|
+
contentType: {
|
|
1156
|
+
$in: contentTypeUids
|
|
1157
|
+
},
|
|
1158
|
+
// We only want to validate actions that are going to be published
|
|
1159
|
+
type: "publish",
|
|
1160
|
+
release: {
|
|
1161
|
+
releasedAt: {
|
|
1162
|
+
$null: true
|
|
1036
1163
|
}
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1164
|
+
}
|
|
1165
|
+
},
|
|
1166
|
+
populate: { release: true }
|
|
1167
|
+
});
|
|
1168
|
+
const releasesUpdated = [];
|
|
1169
|
+
await utils.async.map(actions, async (action) => {
|
|
1170
|
+
const isValid = await getDraftEntryValidStatus(
|
|
1171
|
+
{
|
|
1172
|
+
contentType: action.contentType,
|
|
1173
|
+
documentId: action.entryDocumentId,
|
|
1174
|
+
locale: action.locale
|
|
1175
|
+
},
|
|
1176
|
+
{ strapi: strapi2 }
|
|
1177
|
+
);
|
|
1178
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1040
1179
|
where: {
|
|
1041
|
-
id:
|
|
1180
|
+
id: action.id
|
|
1042
1181
|
},
|
|
1043
1182
|
data: {
|
|
1044
|
-
|
|
1183
|
+
isEntryValid: isValid
|
|
1045
1184
|
}
|
|
1046
1185
|
});
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
where: {
|
|
1050
|
-
id: releaseId
|
|
1051
|
-
},
|
|
1052
|
-
data: {
|
|
1053
|
-
status: "empty"
|
|
1186
|
+
if (!releasesUpdated.includes(action.release.id)) {
|
|
1187
|
+
releasesUpdated.push(action.release.id);
|
|
1054
1188
|
}
|
|
1189
|
+
return {
|
|
1190
|
+
id: action.id,
|
|
1191
|
+
isEntryValid: isValid
|
|
1192
|
+
};
|
|
1055
1193
|
});
|
|
1194
|
+
if (releasesUpdated.length > 0) {
|
|
1195
|
+
await utils.async.map(releasesUpdated, async (releaseId) => {
|
|
1196
|
+
await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1056
1199
|
}
|
|
1057
1200
|
};
|
|
1058
1201
|
};
|
|
1202
|
+
class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
1203
|
+
constructor(message) {
|
|
1204
|
+
super(message);
|
|
1205
|
+
this.name = "AlreadyOnReleaseError";
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1059
1208
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1060
1209
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1061
|
-
const release2 = await strapi2.
|
|
1062
|
-
|
|
1210
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1211
|
+
where: {
|
|
1212
|
+
id: releaseId
|
|
1213
|
+
},
|
|
1214
|
+
populate: {
|
|
1215
|
+
actions: true
|
|
1216
|
+
}
|
|
1063
1217
|
});
|
|
1064
1218
|
if (!release2) {
|
|
1065
1219
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1066
1220
|
}
|
|
1067
1221
|
const isEntryInRelease = release2.actions.some(
|
|
1068
|
-
(action) =>
|
|
1222
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1069
1223
|
);
|
|
1070
1224
|
if (isEntryInRelease) {
|
|
1071
|
-
throw new
|
|
1072
|
-
`Entry with
|
|
1225
|
+
throw new AlreadyOnReleaseError(
|
|
1226
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1073
1227
|
);
|
|
1074
1228
|
}
|
|
1075
1229
|
},
|
|
1076
|
-
|
|
1230
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1077
1231
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1078
1232
|
if (!contentType) {
|
|
1079
1233
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1080
1234
|
}
|
|
1081
|
-
if (!contentType
|
|
1235
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1082
1236
|
throw new utils.errors.ValidationError(
|
|
1083
1237
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1084
1238
|
);
|
|
1085
1239
|
}
|
|
1240
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1241
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1242
|
+
}
|
|
1086
1243
|
},
|
|
1087
1244
|
async validatePendingReleasesLimit() {
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1091
|
-
);
|
|
1245
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1246
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1092
1247
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1093
1248
|
filters: {
|
|
1094
1249
|
releasedAt: {
|
|
@@ -1101,8 +1256,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1101
1256
|
}
|
|
1102
1257
|
},
|
|
1103
1258
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1104
|
-
const pendingReleases = await strapi2.
|
|
1105
|
-
|
|
1259
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1260
|
+
where: {
|
|
1106
1261
|
releasedAt: {
|
|
1107
1262
|
$null: true
|
|
1108
1263
|
},
|
|
@@ -1131,7 +1286,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1131
1286
|
}
|
|
1132
1287
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1133
1288
|
try {
|
|
1134
|
-
await getService("release").publish(releaseId);
|
|
1289
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1135
1290
|
} catch (error) {
|
|
1136
1291
|
}
|
|
1137
1292
|
this.cancel(releaseId);
|
|
@@ -1173,85 +1328,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1173
1328
|
}
|
|
1174
1329
|
};
|
|
1175
1330
|
};
|
|
1331
|
+
const DEFAULT_SETTINGS = {
|
|
1332
|
+
defaultTimezone: null
|
|
1333
|
+
};
|
|
1334
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1335
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1336
|
+
return {
|
|
1337
|
+
async update({ settings: settings2 }) {
|
|
1338
|
+
const store = await getStore();
|
|
1339
|
+
store.set({ key: "settings", value: settings2 });
|
|
1340
|
+
return settings2;
|
|
1341
|
+
},
|
|
1342
|
+
async find() {
|
|
1343
|
+
const store = await getStore();
|
|
1344
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1345
|
+
return {
|
|
1346
|
+
...DEFAULT_SETTINGS,
|
|
1347
|
+
...settings2 || {}
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
};
|
|
1351
|
+
};
|
|
1176
1352
|
const services = {
|
|
1177
1353
|
release: createReleaseService,
|
|
1354
|
+
"release-action": createReleaseActionService,
|
|
1178
1355
|
"release-validation": createReleaseValidationService,
|
|
1179
|
-
|
|
1356
|
+
scheduling: createSchedulingService,
|
|
1357
|
+
settings: createSettingsService
|
|
1180
1358
|
};
|
|
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()
|
|
1359
|
+
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1360
|
+
name: utils.yup.string().trim().required(),
|
|
1361
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1362
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1363
|
+
is: (value) => value !== null && value !== void 0,
|
|
1364
|
+
then: utils.yup.string().required(),
|
|
1365
|
+
otherwise: utils.yup.string().nullable()
|
|
1199
1366
|
})
|
|
1200
1367
|
}).required().noUnknown();
|
|
1368
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1369
|
+
contentType: utils.yup.string().required(),
|
|
1370
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1371
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1372
|
+
locale: utils.yup.string().nullable()
|
|
1373
|
+
}).required().noUnknown();
|
|
1201
1374
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1375
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1376
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1377
|
+
);
|
|
1202
1378
|
const releaseController = {
|
|
1203
|
-
|
|
1204
|
-
|
|
1379
|
+
/**
|
|
1380
|
+
* Find releases based on documents attached or not to the release.
|
|
1381
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1382
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1383
|
+
*/
|
|
1384
|
+
async findByDocumentAttached(ctx) {
|
|
1385
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1205
1386
|
ability: ctx.state.userAbility,
|
|
1206
1387
|
model: RELEASE_MODEL_UID
|
|
1207
1388
|
});
|
|
1208
1389
|
await permissionsManager.validateQuery(ctx.query);
|
|
1209
1390
|
const releaseService = getService("release", { strapi });
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1391
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1392
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1393
|
+
const model = strapi.getModel(query.contentType);
|
|
1394
|
+
if (model.kind && model.kind === "singleType") {
|
|
1395
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1396
|
+
if (!document) {
|
|
1397
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1398
|
+
}
|
|
1399
|
+
query.entryDocumentId = document.documentId;
|
|
1400
|
+
}
|
|
1401
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1402
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1403
|
+
if (isEntryAttached) {
|
|
1404
|
+
const releases = await releaseService.findMany({
|
|
1405
|
+
where: {
|
|
1406
|
+
releasedAt: null,
|
|
1225
1407
|
actions: {
|
|
1226
|
-
|
|
1227
|
-
|
|
1408
|
+
contentType,
|
|
1409
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1410
|
+
locale: locale ?? null
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
populate: {
|
|
1414
|
+
actions: {
|
|
1415
|
+
fields: ["type"],
|
|
1416
|
+
filters: {
|
|
1417
|
+
contentType,
|
|
1418
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1419
|
+
locale: locale ?? null
|
|
1228
1420
|
}
|
|
1229
1421
|
}
|
|
1230
|
-
}
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
ctx.body = { data: releases };
|
|
1425
|
+
} else {
|
|
1426
|
+
const relatedReleases = await releaseService.findMany({
|
|
1427
|
+
where: {
|
|
1428
|
+
releasedAt: null,
|
|
1429
|
+
actions: {
|
|
1430
|
+
contentType,
|
|
1431
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1432
|
+
locale: locale ?? null
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1231
1435
|
});
|
|
1232
|
-
const
|
|
1436
|
+
const releases = await releaseService.findMany({
|
|
1233
1437
|
where: {
|
|
1438
|
+
$or: [
|
|
1439
|
+
{
|
|
1440
|
+
id: {
|
|
1441
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
{
|
|
1445
|
+
actions: null
|
|
1446
|
+
}
|
|
1447
|
+
],
|
|
1234
1448
|
releasedAt: null
|
|
1235
1449
|
}
|
|
1236
1450
|
});
|
|
1237
|
-
ctx.body = { data
|
|
1451
|
+
ctx.body = { data: releases };
|
|
1238
1452
|
}
|
|
1239
1453
|
},
|
|
1454
|
+
async findPage(ctx) {
|
|
1455
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1456
|
+
ability: ctx.state.userAbility,
|
|
1457
|
+
model: RELEASE_MODEL_UID
|
|
1458
|
+
});
|
|
1459
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1460
|
+
const releaseService = getService("release", { strapi });
|
|
1461
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1462
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1463
|
+
const data = results.map((release2) => {
|
|
1464
|
+
const { actions, ...releaseData } = release2;
|
|
1465
|
+
return {
|
|
1466
|
+
...releaseData,
|
|
1467
|
+
actions: {
|
|
1468
|
+
meta: {
|
|
1469
|
+
count: actions.count
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
});
|
|
1474
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1475
|
+
where: {
|
|
1476
|
+
releasedAt: null
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1480
|
+
},
|
|
1240
1481
|
async findOne(ctx) {
|
|
1241
1482
|
const id = ctx.params.id;
|
|
1242
1483
|
const releaseService = getService("release", { strapi });
|
|
1484
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1243
1485
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1244
1486
|
if (!release2) {
|
|
1245
1487
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1246
1488
|
}
|
|
1247
|
-
const count = await
|
|
1489
|
+
const count = await releaseActionService.countActions({
|
|
1248
1490
|
filters: {
|
|
1249
1491
|
release: id
|
|
1250
1492
|
}
|
|
1251
1493
|
});
|
|
1252
1494
|
const sanitizedRelease = {
|
|
1253
1495
|
...release2,
|
|
1254
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1496
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1255
1497
|
};
|
|
1256
1498
|
const data = {
|
|
1257
1499
|
...sanitizedRelease,
|
|
@@ -1263,19 +1505,63 @@ const releaseController = {
|
|
|
1263
1505
|
};
|
|
1264
1506
|
ctx.body = { data };
|
|
1265
1507
|
},
|
|
1508
|
+
async mapEntriesToReleases(ctx) {
|
|
1509
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1510
|
+
if (!contentTypeUid || !documentIds) {
|
|
1511
|
+
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1512
|
+
}
|
|
1513
|
+
const releaseService = getService("release", { strapi });
|
|
1514
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1515
|
+
where: {
|
|
1516
|
+
releasedAt: null,
|
|
1517
|
+
actions: {
|
|
1518
|
+
contentType: contentTypeUid,
|
|
1519
|
+
entryDocumentId: {
|
|
1520
|
+
$in: documentIds
|
|
1521
|
+
},
|
|
1522
|
+
locale
|
|
1523
|
+
}
|
|
1524
|
+
},
|
|
1525
|
+
populate: {
|
|
1526
|
+
actions: true
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1530
|
+
(acc, release2) => {
|
|
1531
|
+
release2.actions.forEach((action) => {
|
|
1532
|
+
if (action.contentType !== contentTypeUid) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
if (locale && action.locale !== locale) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
if (!acc[action.entryDocumentId]) {
|
|
1539
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1540
|
+
} else {
|
|
1541
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
return acc;
|
|
1545
|
+
},
|
|
1546
|
+
{}
|
|
1547
|
+
);
|
|
1548
|
+
ctx.body = {
|
|
1549
|
+
data: mappedEntriesInReleases
|
|
1550
|
+
};
|
|
1551
|
+
},
|
|
1266
1552
|
async create(ctx) {
|
|
1267
1553
|
const user = ctx.state.user;
|
|
1268
1554
|
const releaseArgs = ctx.request.body;
|
|
1269
1555
|
await validateRelease(releaseArgs);
|
|
1270
1556
|
const releaseService = getService("release", { strapi });
|
|
1271
1557
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1272
|
-
const permissionsManager = strapi.admin
|
|
1558
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1273
1559
|
ability: ctx.state.userAbility,
|
|
1274
1560
|
model: RELEASE_MODEL_UID
|
|
1275
1561
|
});
|
|
1276
|
-
ctx.
|
|
1562
|
+
ctx.created({
|
|
1277
1563
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1278
|
-
};
|
|
1564
|
+
});
|
|
1279
1565
|
},
|
|
1280
1566
|
async update(ctx) {
|
|
1281
1567
|
const user = ctx.state.user;
|
|
@@ -1284,7 +1570,7 @@ const releaseController = {
|
|
|
1284
1570
|
await validateRelease(releaseArgs);
|
|
1285
1571
|
const releaseService = getService("release", { strapi });
|
|
1286
1572
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1287
|
-
const permissionsManager = strapi.admin
|
|
1573
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1288
1574
|
ability: ctx.state.userAbility,
|
|
1289
1575
|
model: RELEASE_MODEL_UID
|
|
1290
1576
|
});
|
|
@@ -1301,18 +1587,18 @@ const releaseController = {
|
|
|
1301
1587
|
};
|
|
1302
1588
|
},
|
|
1303
1589
|
async publish(ctx) {
|
|
1304
|
-
const user = ctx.state.user;
|
|
1305
1590
|
const id = ctx.params.id;
|
|
1306
1591
|
const releaseService = getService("release", { strapi });
|
|
1307
|
-
const
|
|
1592
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1593
|
+
const release2 = await releaseService.publish(id);
|
|
1308
1594
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1309
|
-
|
|
1595
|
+
releaseActionService.countActions({
|
|
1310
1596
|
filters: {
|
|
1311
1597
|
release: id,
|
|
1312
1598
|
type: "publish"
|
|
1313
1599
|
}
|
|
1314
1600
|
}),
|
|
1315
|
-
|
|
1601
|
+
releaseActionService.countActions({
|
|
1316
1602
|
filters: {
|
|
1317
1603
|
release: id,
|
|
1318
1604
|
type: "unpublish"
|
|
@@ -1330,57 +1616,106 @@ const releaseController = {
|
|
|
1330
1616
|
}
|
|
1331
1617
|
};
|
|
1332
1618
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
}).required(),
|
|
1619
|
+
contentType: utils.yup.string().required(),
|
|
1620
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1621
|
+
locale: utils.yup.string(),
|
|
1337
1622
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1338
1623
|
});
|
|
1339
1624
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1340
1625
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1341
1626
|
});
|
|
1627
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1628
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1629
|
+
});
|
|
1342
1630
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1343
1631
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1632
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1344
1633
|
const releaseActionController = {
|
|
1345
1634
|
async create(ctx) {
|
|
1346
1635
|
const releaseId = ctx.params.releaseId;
|
|
1347
1636
|
const releaseActionArgs = ctx.request.body;
|
|
1348
1637
|
await validateReleaseAction(releaseActionArgs);
|
|
1349
|
-
const
|
|
1350
|
-
const releaseAction2 = await
|
|
1351
|
-
ctx.
|
|
1638
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1639
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1640
|
+
ctx.created({
|
|
1352
1641
|
data: releaseAction2
|
|
1353
|
-
};
|
|
1642
|
+
});
|
|
1643
|
+
},
|
|
1644
|
+
async createMany(ctx) {
|
|
1645
|
+
const releaseId = ctx.params.releaseId;
|
|
1646
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1647
|
+
await Promise.all(
|
|
1648
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1649
|
+
);
|
|
1650
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1651
|
+
const releaseService = getService("release", { strapi });
|
|
1652
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1653
|
+
const releaseActions2 = await Promise.all(
|
|
1654
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1655
|
+
try {
|
|
1656
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1657
|
+
disableUpdateReleaseStatus: true
|
|
1658
|
+
});
|
|
1659
|
+
return action;
|
|
1660
|
+
} catch (error) {
|
|
1661
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1662
|
+
return null;
|
|
1663
|
+
}
|
|
1664
|
+
throw error;
|
|
1665
|
+
}
|
|
1666
|
+
})
|
|
1667
|
+
);
|
|
1668
|
+
return releaseActions2;
|
|
1669
|
+
});
|
|
1670
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1671
|
+
if (newReleaseActions.length > 0) {
|
|
1672
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1673
|
+
}
|
|
1674
|
+
ctx.created({
|
|
1675
|
+
data: newReleaseActions,
|
|
1676
|
+
meta: {
|
|
1677
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1678
|
+
totalEntries: releaseActions.length
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1354
1681
|
},
|
|
1355
1682
|
async findMany(ctx) {
|
|
1356
1683
|
const releaseId = ctx.params.releaseId;
|
|
1357
|
-
const permissionsManager = strapi.admin
|
|
1684
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1358
1685
|
ability: ctx.state.userAbility,
|
|
1359
1686
|
model: RELEASE_ACTION_MODEL_UID
|
|
1360
1687
|
});
|
|
1688
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1689
|
+
if (ctx.query.groupBy) {
|
|
1690
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1691
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1695
|
+
delete ctx.query.groupBy;
|
|
1361
1696
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1362
|
-
const
|
|
1363
|
-
const { results, pagination } = await
|
|
1364
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1697
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1698
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1365
1699
|
...query
|
|
1366
1700
|
});
|
|
1367
1701
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1368
1702
|
if (acc[action.contentType]) {
|
|
1369
1703
|
return acc;
|
|
1370
1704
|
}
|
|
1371
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1705
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1372
1706
|
ability: ctx.state.userAbility,
|
|
1373
1707
|
model: action.contentType
|
|
1374
1708
|
});
|
|
1375
1709
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1376
1710
|
return acc;
|
|
1377
1711
|
}, {});
|
|
1378
|
-
const sanitizedResults = await utils.
|
|
1712
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1379
1713
|
...action,
|
|
1380
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1714
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1381
1715
|
}));
|
|
1382
|
-
const groupedData = await
|
|
1383
|
-
const contentTypes2 =
|
|
1716
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1717
|
+
const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
|
|
1718
|
+
const releaseService = getService("release", { strapi });
|
|
1384
1719
|
const components = await releaseService.getAllComponents();
|
|
1385
1720
|
ctx.body = {
|
|
1386
1721
|
data: groupedData,
|
|
@@ -1396,8 +1731,8 @@ const releaseActionController = {
|
|
|
1396
1731
|
const releaseId = ctx.params.releaseId;
|
|
1397
1732
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1398
1733
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1399
|
-
const
|
|
1400
|
-
const updatedAction = await
|
|
1734
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1735
|
+
const updatedAction = await releaseActionService.update(
|
|
1401
1736
|
actionId,
|
|
1402
1737
|
releaseId,
|
|
1403
1738
|
releaseActionUpdateArgs
|
|
@@ -1409,17 +1744,71 @@ const releaseActionController = {
|
|
|
1409
1744
|
async delete(ctx) {
|
|
1410
1745
|
const actionId = ctx.params.actionId;
|
|
1411
1746
|
const releaseId = ctx.params.releaseId;
|
|
1412
|
-
const
|
|
1413
|
-
const deletedReleaseAction = await
|
|
1747
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1748
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1414
1749
|
ctx.body = {
|
|
1415
1750
|
data: deletedReleaseAction
|
|
1416
1751
|
};
|
|
1417
1752
|
}
|
|
1418
1753
|
};
|
|
1419
|
-
const
|
|
1754
|
+
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1755
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1756
|
+
}).required().noUnknown();
|
|
1757
|
+
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1758
|
+
const settingsController = {
|
|
1759
|
+
async find(ctx) {
|
|
1760
|
+
const settingsService = getService("settings", { strapi });
|
|
1761
|
+
const settings2 = await settingsService.find();
|
|
1762
|
+
ctx.body = { data: settings2 };
|
|
1763
|
+
},
|
|
1764
|
+
async update(ctx) {
|
|
1765
|
+
const settingsBody = ctx.request.body;
|
|
1766
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1767
|
+
const settingsService = getService("settings", { strapi });
|
|
1768
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1769
|
+
ctx.body = { data: updatedSettings };
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
const controllers = {
|
|
1773
|
+
release: releaseController,
|
|
1774
|
+
"release-action": releaseActionController,
|
|
1775
|
+
settings: settingsController
|
|
1776
|
+
};
|
|
1420
1777
|
const release = {
|
|
1421
1778
|
type: "admin",
|
|
1422
1779
|
routes: [
|
|
1780
|
+
{
|
|
1781
|
+
method: "GET",
|
|
1782
|
+
path: "/mapEntriesToReleases",
|
|
1783
|
+
handler: "release.mapEntriesToReleases",
|
|
1784
|
+
config: {
|
|
1785
|
+
policies: [
|
|
1786
|
+
"admin::isAuthenticatedAdmin",
|
|
1787
|
+
{
|
|
1788
|
+
name: "admin::hasPermissions",
|
|
1789
|
+
config: {
|
|
1790
|
+
actions: ["plugin::content-releases.read"]
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
]
|
|
1794
|
+
}
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
method: "GET",
|
|
1798
|
+
path: "/getByDocumentAttached",
|
|
1799
|
+
handler: "release.findByDocumentAttached",
|
|
1800
|
+
config: {
|
|
1801
|
+
policies: [
|
|
1802
|
+
"admin::isAuthenticatedAdmin",
|
|
1803
|
+
{
|
|
1804
|
+
name: "admin::hasPermissions",
|
|
1805
|
+
config: {
|
|
1806
|
+
actions: ["plugin::content-releases.read"]
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
]
|
|
1810
|
+
}
|
|
1811
|
+
},
|
|
1423
1812
|
{
|
|
1424
1813
|
method: "POST",
|
|
1425
1814
|
path: "/",
|
|
@@ -1439,7 +1828,7 @@ const release = {
|
|
|
1439
1828
|
{
|
|
1440
1829
|
method: "GET",
|
|
1441
1830
|
path: "/",
|
|
1442
|
-
handler: "release.
|
|
1831
|
+
handler: "release.findPage",
|
|
1443
1832
|
config: {
|
|
1444
1833
|
policies: [
|
|
1445
1834
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1537,6 +1926,22 @@ const releaseAction = {
|
|
|
1537
1926
|
]
|
|
1538
1927
|
}
|
|
1539
1928
|
},
|
|
1929
|
+
{
|
|
1930
|
+
method: "POST",
|
|
1931
|
+
path: "/:releaseId/actions/bulk",
|
|
1932
|
+
handler: "release-action.createMany",
|
|
1933
|
+
config: {
|
|
1934
|
+
policies: [
|
|
1935
|
+
"admin::isAuthenticatedAdmin",
|
|
1936
|
+
{
|
|
1937
|
+
name: "admin::hasPermissions",
|
|
1938
|
+
config: {
|
|
1939
|
+
actions: ["plugin::content-releases.create-action"]
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
]
|
|
1943
|
+
}
|
|
1944
|
+
},
|
|
1540
1945
|
{
|
|
1541
1946
|
method: "GET",
|
|
1542
1947
|
path: "/:releaseId/actions",
|
|
@@ -1587,13 +1992,50 @@ const releaseAction = {
|
|
|
1587
1992
|
}
|
|
1588
1993
|
]
|
|
1589
1994
|
};
|
|
1995
|
+
const settings = {
|
|
1996
|
+
type: "admin",
|
|
1997
|
+
routes: [
|
|
1998
|
+
{
|
|
1999
|
+
method: "GET",
|
|
2000
|
+
path: "/settings",
|
|
2001
|
+
handler: "settings.find",
|
|
2002
|
+
config: {
|
|
2003
|
+
policies: [
|
|
2004
|
+
"admin::isAuthenticatedAdmin",
|
|
2005
|
+
{
|
|
2006
|
+
name: "admin::hasPermissions",
|
|
2007
|
+
config: {
|
|
2008
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
]
|
|
2012
|
+
}
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
method: "PUT",
|
|
2016
|
+
path: "/settings",
|
|
2017
|
+
handler: "settings.update",
|
|
2018
|
+
config: {
|
|
2019
|
+
policies: [
|
|
2020
|
+
"admin::isAuthenticatedAdmin",
|
|
2021
|
+
{
|
|
2022
|
+
name: "admin::hasPermissions",
|
|
2023
|
+
config: {
|
|
2024
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
]
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
]
|
|
2031
|
+
};
|
|
1590
2032
|
const routes = {
|
|
2033
|
+
settings,
|
|
1591
2034
|
release,
|
|
1592
2035
|
"release-action": releaseAction
|
|
1593
2036
|
};
|
|
1594
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1595
2037
|
const getPlugin = () => {
|
|
1596
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
2038
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1597
2039
|
return {
|
|
1598
2040
|
register,
|
|
1599
2041
|
bootstrap,
|
|
@@ -1605,6 +2047,9 @@ const getPlugin = () => {
|
|
|
1605
2047
|
};
|
|
1606
2048
|
}
|
|
1607
2049
|
return {
|
|
2050
|
+
// Always return register, it handles its own feature check
|
|
2051
|
+
register,
|
|
2052
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
1608
2053
|
contentTypes
|
|
1609
2054
|
};
|
|
1610
2055
|
};
|