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