@strapi/content-releases 0.0.0-next.73143c28059b343ba62d98c29672ab114562fbbc → 0.0.0-next.7315bad3dd6542d457c3c837db874e3e6336ae9f
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-BogHVHwI.js +1578 -0
- package/dist/_chunks/App-BogHVHwI.js.map +1 -0
- package/dist/_chunks/App-Ckb7_0Kj.mjs +1558 -0
- package/dist/_chunks/App-Ckb7_0Kj.mjs.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
- package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-CFWj9DKn.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-CFWj9DKn.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-DhhwsfOv.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-DhhwsfOv.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-CBRMnJQ5.js +1404 -0
- package/dist/_chunks/index-CBRMnJQ5.js.map +1 -0
- package/dist/_chunks/index-RcSLPK74.mjs +1386 -0
- package/dist/_chunks/index-RcSLPK74.mjs.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 +1108 -664
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1108 -662
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -0
- package/dist/server/src/constants.d.ts +21 -0
- package/dist/server/src/constants.d.ts.map +1 -0
- package/dist/server/src/content-types/index.d.ts +97 -0
- package/dist/server/src/content-types/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/index.d.ts +48 -0
- package/dist/server/src/content-types/release/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/schema.d.ts +47 -0
- package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/index.d.ts +48 -0
- package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/schema.d.ts +47 -0
- package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
- package/dist/server/src/controllers/index.d.ts +25 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -0
- package/dist/server/src/controllers/release-action.d.ts +10 -0
- package/dist/server/src/controllers/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/release.d.ts +18 -0
- package/dist/server/src/controllers/release.d.ts.map +1 -0
- package/dist/server/src/controllers/settings.d.ts +11 -0
- package/dist/server/src/controllers/settings.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release-action.d.ts +14 -0
- package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release.d.ts +4 -0
- package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/settings.d.ts +3 -0
- package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/destroy.d.ts.map +1 -0
- package/dist/server/src/index.d.ts +2111 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/middlewares/documents.d.ts +6 -0
- package/dist/server/src/middlewares/documents.d.ts.map +1 -0
- package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
- package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
- package/dist/server/src/migrations/index.d.ts +13 -0
- package/dist/server/src/migrations/index.d.ts.map +1 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/register.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts +51 -0
- package/dist/server/src/routes/index.d.ts.map +1 -0
- package/dist/server/src/routes/release-action.d.ts +18 -0
- package/dist/server/src/routes/release-action.d.ts.map +1 -0
- package/dist/server/src/routes/release.d.ts +18 -0
- package/dist/server/src/routes/release.d.ts.map +1 -0
- package/dist/server/src/routes/settings.d.ts +18 -0
- package/dist/server/src/routes/settings.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +1824 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/release-action.d.ts +34 -0
- package/dist/server/src/services/release-action.d.ts.map +1 -0
- package/dist/server/src/services/release.d.ts +31 -0
- package/dist/server/src/services/release.d.ts.map +1 -0
- package/dist/server/src/services/scheduling.d.ts +18 -0
- package/dist/server/src/services/scheduling.d.ts.map +1 -0
- package/dist/server/src/services/settings.d.ts +13 -0
- package/dist/server/src/services/settings.d.ts.map +1 -0
- package/dist/server/src/services/validation.d.ts +18 -0
- package/dist/server/src/services/validation.d.ts.map +1 -0
- package/dist/server/src/utils/index.d.ts +35 -0
- package/dist/server/src/utils/index.d.ts.map +1 -0
- package/dist/shared/contracts/release-actions.d.ts +137 -0
- package/dist/shared/contracts/release-actions.d.ts.map +1 -0
- package/dist/shared/contracts/releases.d.ts +184 -0
- package/dist/shared/contracts/releases.d.ts.map +1 -0
- package/dist/shared/contracts/settings.d.ts +39 -0
- package/dist/shared/contracts/settings.d.ts.map +1 -0
- package/dist/shared/types.d.ts +24 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/package.json +35 -39
- package/dist/_chunks/App-g3vtS2Wa.mjs +0 -1287
- package/dist/_chunks/App-g3vtS2Wa.mjs.map +0 -1
- package/dist/_chunks/App-lnXbSPgp.js +0 -1310
- package/dist/_chunks/App-lnXbSPgp.js.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
- package/dist/_chunks/en-WuuhP6Bn.mjs.map +0 -1
- package/dist/_chunks/en-gcJJ5htG.js.map +0 -1
- package/dist/_chunks/index-ItlgrLcr.js +0 -1034
- package/dist/_chunks/index-ItlgrLcr.js.map +0 -1
- package/dist/_chunks/index-uGex_IIQ.mjs +0 -1013
- package/dist/_chunks/index-uGex_IIQ.mjs.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.js
CHANGED
|
@@ -3,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,187 +261,272 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
202
261
|
release: true
|
|
203
262
|
}
|
|
204
263
|
});
|
|
205
|
-
await utils.
|
|
206
|
-
if (action.entry) {
|
|
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
|
});
|
|
232
291
|
}
|
|
233
292
|
}
|
|
234
|
-
|
|
293
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
294
|
+
if (!oldContentTypes) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
298
|
+
if (!i18nPlugin) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
for (const uid in contentTypes2) {
|
|
302
|
+
if (!oldContentTypes[uid]) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const oldContentType = oldContentTypes[uid];
|
|
306
|
+
const contentType = contentTypes2[uid];
|
|
307
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
308
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
309
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
310
|
+
locale: null
|
|
311
|
+
}).where({ contentType: uid }).execute();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
316
|
+
if (!oldContentTypes) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
320
|
+
if (!i18nPlugin) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
for (const uid in contentTypes2) {
|
|
324
|
+
if (!oldContentTypes[uid]) {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const oldContentType = oldContentTypes[uid];
|
|
328
|
+
const contentType = contentTypes2[uid];
|
|
329
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
330
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
331
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
332
|
+
const defaultLocale = await getDefaultLocale();
|
|
333
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
334
|
+
locale: defaultLocale
|
|
335
|
+
}).where({ contentType: uid }).execute();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
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
|
+
};
|
|
235
371
|
const register = async ({ strapi: strapi2 }) => {
|
|
236
|
-
if (features
|
|
237
|
-
await strapi2.admin
|
|
238
|
-
strapi2.
|
|
239
|
-
strapi2.hook("strapi::content-types.
|
|
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);
|
|
376
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
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);
|
|
240
481
|
}
|
|
241
482
|
};
|
|
242
|
-
const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
|
|
243
483
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
244
|
-
if (features
|
|
484
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
245
485
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
246
486
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
247
487
|
);
|
|
248
488
|
strapi2.db.lifecycles.subscribe({
|
|
249
489
|
models: contentTypesWithDraftAndPublish,
|
|
250
|
-
async afterDelete(event) {
|
|
251
|
-
try {
|
|
252
|
-
const { model, result } = event;
|
|
253
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
254
|
-
const { id } = result;
|
|
255
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
256
|
-
where: {
|
|
257
|
-
actions: {
|
|
258
|
-
target_type: model.uid,
|
|
259
|
-
target_id: id
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
264
|
-
where: {
|
|
265
|
-
target_type: model.uid,
|
|
266
|
-
target_id: id
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
for (const release2 of releases) {
|
|
270
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
} catch (error) {
|
|
274
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
/**
|
|
278
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
279
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
280
|
-
*/
|
|
281
|
-
async beforeDeleteMany(event) {
|
|
282
|
-
const { model, params } = event;
|
|
283
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
284
|
-
const { where } = params;
|
|
285
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
286
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
490
|
/**
|
|
290
|
-
*
|
|
291
|
-
* 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
|
|
292
492
|
*/
|
|
293
493
|
async afterDeleteMany(event) {
|
|
294
494
|
try {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
target_id: {
|
|
303
|
-
$in: entriesToDelete.map(
|
|
304
|
-
(entry) => entry.id
|
|
305
|
-
)
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
311
|
-
where: {
|
|
312
|
-
target_type: model.uid,
|
|
313
|
-
target_id: {
|
|
314
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
315
|
-
}
|
|
316
|
-
}
|
|
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 }
|
|
317
502
|
});
|
|
318
|
-
for (const release2 of releases) {
|
|
319
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
320
|
-
}
|
|
321
503
|
}
|
|
322
504
|
} catch (error) {
|
|
323
505
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
324
506
|
error
|
|
325
507
|
});
|
|
326
508
|
}
|
|
327
|
-
},
|
|
328
|
-
async afterUpdate(event) {
|
|
329
|
-
try {
|
|
330
|
-
const { model, result } = event;
|
|
331
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
332
|
-
const isEntryValid = await getEntryValidStatus(
|
|
333
|
-
model.uid,
|
|
334
|
-
result,
|
|
335
|
-
{
|
|
336
|
-
strapi: strapi2
|
|
337
|
-
}
|
|
338
|
-
);
|
|
339
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
340
|
-
where: {
|
|
341
|
-
target_type: model.uid,
|
|
342
|
-
target_id: result.id
|
|
343
|
-
},
|
|
344
|
-
data: {
|
|
345
|
-
isEntryValid
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
349
|
-
where: {
|
|
350
|
-
actions: {
|
|
351
|
-
target_type: model.uid,
|
|
352
|
-
target_id: result.id
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
for (const release2 of releases) {
|
|
357
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
} catch (error) {
|
|
361
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
362
|
-
}
|
|
363
509
|
}
|
|
364
510
|
});
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
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
|
+
});
|
|
376
522
|
}
|
|
377
523
|
};
|
|
378
524
|
const destroy = async ({ strapi: strapi2 }) => {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
job.cancel();
|
|
385
|
-
}
|
|
525
|
+
const scheduledJobs = getService("scheduling", {
|
|
526
|
+
strapi: strapi2
|
|
527
|
+
}).getAll();
|
|
528
|
+
for (const [, job] of scheduledJobs) {
|
|
529
|
+
job.cancel();
|
|
386
530
|
}
|
|
387
531
|
};
|
|
388
532
|
const schema$1 = {
|
|
@@ -457,15 +601,13 @@ const schema = {
|
|
|
457
601
|
enum: ["publish", "unpublish"],
|
|
458
602
|
required: true
|
|
459
603
|
},
|
|
460
|
-
entry: {
|
|
461
|
-
type: "relation",
|
|
462
|
-
relation: "morphToOne",
|
|
463
|
-
configurable: false
|
|
464
|
-
},
|
|
465
604
|
contentType: {
|
|
466
605
|
type: "string",
|
|
467
606
|
required: true
|
|
468
607
|
},
|
|
608
|
+
entryDocumentId: {
|
|
609
|
+
type: "string"
|
|
610
|
+
},
|
|
469
611
|
locale: {
|
|
470
612
|
type: "string"
|
|
471
613
|
},
|
|
@@ -487,18 +629,6 @@ const contentTypes = {
|
|
|
487
629
|
release: release$1,
|
|
488
630
|
"release-action": releaseAction$1
|
|
489
631
|
};
|
|
490
|
-
const getGroupName = (queryValue) => {
|
|
491
|
-
switch (queryValue) {
|
|
492
|
-
case "contentType":
|
|
493
|
-
return "contentType.displayName";
|
|
494
|
-
case "action":
|
|
495
|
-
return "type";
|
|
496
|
-
case "locale":
|
|
497
|
-
return ___default.default.getOr("No locale", "locale.name");
|
|
498
|
-
default:
|
|
499
|
-
return "contentType.displayName";
|
|
500
|
-
}
|
|
501
|
-
};
|
|
502
632
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
503
633
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
504
634
|
strapi2.eventHub.emit(event, {
|
|
@@ -507,6 +637,33 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
507
637
|
release: release2
|
|
508
638
|
});
|
|
509
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
|
+
};
|
|
510
667
|
return {
|
|
511
668
|
async create(releaseData, { user }) {
|
|
512
669
|
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
@@ -520,13 +677,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
520
677
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
521
678
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
522
679
|
]);
|
|
523
|
-
const release2 = await strapi2.
|
|
680
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
524
681
|
data: {
|
|
525
682
|
...releaseWithCreatorFields,
|
|
526
683
|
status: "empty"
|
|
527
684
|
}
|
|
528
685
|
});
|
|
529
|
-
if (
|
|
686
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
530
687
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
531
688
|
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
532
689
|
}
|
|
@@ -534,94 +691,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
534
691
|
return release2;
|
|
535
692
|
},
|
|
536
693
|
async findOne(id, query = {}) {
|
|
537
|
-
const
|
|
538
|
-
|
|
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 }
|
|
539
698
|
});
|
|
540
699
|
return release2;
|
|
541
700
|
},
|
|
542
701
|
findPage(query) {
|
|
543
|
-
|
|
544
|
-
|
|
702
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
703
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
704
|
+
...dbQuery,
|
|
545
705
|
populate: {
|
|
546
706
|
actions: {
|
|
547
|
-
// @ts-expect-error Ignore missing properties
|
|
548
707
|
count: true
|
|
549
708
|
}
|
|
550
709
|
}
|
|
551
710
|
});
|
|
552
711
|
},
|
|
553
|
-
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
target_type: contentTypeUid,
|
|
558
|
-
target_id: entryId
|
|
559
|
-
},
|
|
560
|
-
releasedAt: {
|
|
561
|
-
$null: true
|
|
562
|
-
}
|
|
563
|
-
},
|
|
564
|
-
populate: {
|
|
565
|
-
// Filter the action to get only the content type entry
|
|
566
|
-
actions: {
|
|
567
|
-
where: {
|
|
568
|
-
target_type: contentTypeUid,
|
|
569
|
-
target_id: entryId
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
return releases.map((release2) => {
|
|
575
|
-
if (release2.actions?.length) {
|
|
576
|
-
const [actionForEntry] = release2.actions;
|
|
577
|
-
delete release2.actions;
|
|
578
|
-
return {
|
|
579
|
-
...release2,
|
|
580
|
-
action: actionForEntry
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
return release2;
|
|
584
|
-
});
|
|
585
|
-
},
|
|
586
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
587
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
588
|
-
where: {
|
|
589
|
-
releasedAt: {
|
|
590
|
-
$null: true
|
|
591
|
-
},
|
|
592
|
-
actions: {
|
|
593
|
-
target_type: contentTypeUid,
|
|
594
|
-
target_id: entryId
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
599
|
-
where: {
|
|
600
|
-
$or: [
|
|
601
|
-
{
|
|
602
|
-
id: {
|
|
603
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
604
|
-
}
|
|
605
|
-
},
|
|
606
|
-
{
|
|
607
|
-
actions: null
|
|
608
|
-
}
|
|
609
|
-
],
|
|
610
|
-
releasedAt: {
|
|
611
|
-
$null: true
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
return releases.map((release2) => {
|
|
616
|
-
if (release2.actions?.length) {
|
|
617
|
-
const [actionForEntry] = release2.actions;
|
|
618
|
-
delete release2.actions;
|
|
619
|
-
return {
|
|
620
|
-
...release2,
|
|
621
|
-
action: actionForEntry
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
return release2;
|
|
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
|
|
625
716
|
});
|
|
626
717
|
},
|
|
627
718
|
async update(id, releaseData, { user }) {
|
|
@@ -636,157 +727,27 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
636
727
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
637
728
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
638
729
|
]);
|
|
639
|
-
const release2 = await strapi2.
|
|
730
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
640
731
|
if (!release2) {
|
|
641
732
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
642
733
|
}
|
|
643
734
|
if (release2.releasedAt) {
|
|
644
735
|
throw new utils.errors.ValidationError("Release already published");
|
|
645
736
|
}
|
|
646
|
-
const updatedRelease = await strapi2.
|
|
647
|
-
|
|
648
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
649
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
650
|
-
*/
|
|
651
|
-
// @ts-expect-error see above
|
|
737
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
738
|
+
where: { id },
|
|
652
739
|
data: releaseWithCreatorFields
|
|
653
740
|
});
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
schedulingService.cancel(id);
|
|
660
|
-
}
|
|
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);
|
|
661
746
|
}
|
|
662
747
|
this.updateReleaseStatus(id);
|
|
663
748
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
664
749
|
return updatedRelease;
|
|
665
750
|
},
|
|
666
|
-
async createAction(releaseId, action) {
|
|
667
|
-
const { validateEntryContentType, validateUniqueEntry } = getService("release-validation", {
|
|
668
|
-
strapi: strapi2
|
|
669
|
-
});
|
|
670
|
-
await Promise.all([
|
|
671
|
-
validateEntryContentType(action.entry.contentType),
|
|
672
|
-
validateUniqueEntry(releaseId, action)
|
|
673
|
-
]);
|
|
674
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
675
|
-
if (!release2) {
|
|
676
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
677
|
-
}
|
|
678
|
-
if (release2.releasedAt) {
|
|
679
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
680
|
-
}
|
|
681
|
-
const { entry, type } = action;
|
|
682
|
-
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
683
|
-
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
684
|
-
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
685
|
-
data: {
|
|
686
|
-
type,
|
|
687
|
-
contentType: entry.contentType,
|
|
688
|
-
locale: entry.locale,
|
|
689
|
-
isEntryValid,
|
|
690
|
-
entry: {
|
|
691
|
-
id: entry.id,
|
|
692
|
-
__type: entry.contentType,
|
|
693
|
-
__pivot: { field: "entry" }
|
|
694
|
-
},
|
|
695
|
-
release: releaseId
|
|
696
|
-
},
|
|
697
|
-
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
698
|
-
});
|
|
699
|
-
this.updateReleaseStatus(releaseId);
|
|
700
|
-
return releaseAction2;
|
|
701
|
-
},
|
|
702
|
-
async findActions(releaseId, query) {
|
|
703
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
704
|
-
fields: ["id"]
|
|
705
|
-
});
|
|
706
|
-
if (!release2) {
|
|
707
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
708
|
-
}
|
|
709
|
-
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
710
|
-
...query,
|
|
711
|
-
populate: {
|
|
712
|
-
entry: {
|
|
713
|
-
populate: "*"
|
|
714
|
-
}
|
|
715
|
-
},
|
|
716
|
-
filters: {
|
|
717
|
-
release: releaseId
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
},
|
|
721
|
-
async countActions(query) {
|
|
722
|
-
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
723
|
-
},
|
|
724
|
-
async groupActions(actions, groupBy) {
|
|
725
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
726
|
-
if (!acc.includes(action.contentType)) {
|
|
727
|
-
acc.push(action.contentType);
|
|
728
|
-
}
|
|
729
|
-
return acc;
|
|
730
|
-
}, []);
|
|
731
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
732
|
-
contentTypeUids
|
|
733
|
-
);
|
|
734
|
-
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
735
|
-
const formattedData = actions.map((action) => {
|
|
736
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
737
|
-
return {
|
|
738
|
-
...action,
|
|
739
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
740
|
-
contentType: {
|
|
741
|
-
displayName,
|
|
742
|
-
mainFieldValue: action.entry[mainField],
|
|
743
|
-
uid: action.contentType
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
});
|
|
747
|
-
const groupName = getGroupName(groupBy);
|
|
748
|
-
return ___default.default.groupBy(groupName)(formattedData);
|
|
749
|
-
},
|
|
750
|
-
async getLocalesDataForActions() {
|
|
751
|
-
if (!strapi2.plugin("i18n")) {
|
|
752
|
-
return {};
|
|
753
|
-
}
|
|
754
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
755
|
-
return allLocales.reduce((acc, locale) => {
|
|
756
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
757
|
-
return acc;
|
|
758
|
-
}, {});
|
|
759
|
-
},
|
|
760
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
761
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
762
|
-
const contentTypesData = {};
|
|
763
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
764
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
765
|
-
uid: contentTypeUid
|
|
766
|
-
});
|
|
767
|
-
contentTypesData[contentTypeUid] = {
|
|
768
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
769
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
return contentTypesData;
|
|
773
|
-
},
|
|
774
|
-
getContentTypeModelsFromActions(actions) {
|
|
775
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
776
|
-
if (!acc.includes(action.contentType)) {
|
|
777
|
-
acc.push(action.contentType);
|
|
778
|
-
}
|
|
779
|
-
return acc;
|
|
780
|
-
}, []);
|
|
781
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
782
|
-
(acc, contentTypeUid) => {
|
|
783
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
784
|
-
return acc;
|
|
785
|
-
},
|
|
786
|
-
{}
|
|
787
|
-
);
|
|
788
|
-
return contentTypeModelsMap;
|
|
789
|
-
},
|
|
790
751
|
async getAllComponents() {
|
|
791
752
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
792
753
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -800,10 +761,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
800
761
|
return componentsMap;
|
|
801
762
|
},
|
|
802
763
|
async delete(releaseId) {
|
|
803
|
-
const release2 = await strapi2.
|
|
764
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
765
|
+
where: { id: releaseId },
|
|
804
766
|
populate: {
|
|
805
767
|
actions: {
|
|
806
|
-
|
|
768
|
+
select: ["id"]
|
|
807
769
|
}
|
|
808
770
|
}
|
|
809
771
|
});
|
|
@@ -821,9 +783,13 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
821
783
|
}
|
|
822
784
|
}
|
|
823
785
|
});
|
|
824
|
-
await strapi2.
|
|
786
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
787
|
+
where: {
|
|
788
|
+
id: releaseId
|
|
789
|
+
}
|
|
790
|
+
});
|
|
825
791
|
});
|
|
826
|
-
if (
|
|
792
|
+
if (release2.scheduledAt) {
|
|
827
793
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
828
794
|
await schedulingService.cancel(release2.id);
|
|
829
795
|
}
|
|
@@ -831,148 +797,294 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
831
797
|
return release2;
|
|
832
798
|
},
|
|
833
799
|
async publish(releaseId) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
actions: {
|
|
841
|
-
populate: {
|
|
842
|
-
entry: {
|
|
843
|
-
fields: ["id"]
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
);
|
|
850
|
-
if (!releaseWithPopulatedActionEntries) {
|
|
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) {
|
|
851
806
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
852
807
|
}
|
|
853
|
-
if (
|
|
808
|
+
if (lockedRelease.releasedAt) {
|
|
854
809
|
throw new utils.errors.ValidationError("Release already published");
|
|
855
810
|
}
|
|
856
|
-
if (
|
|
857
|
-
throw new utils.errors.ValidationError("
|
|
811
|
+
if (lockedRelease.status === "failed") {
|
|
812
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
858
813
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
884
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
885
|
-
await strapi2.db.transaction(async () => {
|
|
886
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
887
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
888
|
-
const entry = await strapi2.entityService.findOne(uid, id, { populate });
|
|
889
|
-
try {
|
|
890
|
-
if (action === "publish") {
|
|
891
|
-
await entityManagerService.publish(entry, uid);
|
|
892
|
-
} else {
|
|
893
|
-
await entityManagerService.unpublish(entry, uid);
|
|
894
|
-
}
|
|
895
|
-
} catch (error) {
|
|
896
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
|
|
897
|
-
} else {
|
|
898
|
-
throw error;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
903
|
-
const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
|
|
904
|
-
const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
|
|
905
|
-
const entriesToPublish = await strapi2.entityService.findMany(
|
|
906
|
-
contentTypeUid,
|
|
907
|
-
{
|
|
908
|
-
filters: {
|
|
909
|
-
id: {
|
|
910
|
-
$in: entriestoPublishIds
|
|
911
|
-
}
|
|
912
|
-
},
|
|
913
|
-
populate
|
|
914
|
-
}
|
|
915
|
-
);
|
|
916
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(
|
|
917
|
-
contentTypeUid,
|
|
918
|
-
{
|
|
919
|
-
filters: {
|
|
920
|
-
id: {
|
|
921
|
-
$in: entriesToUnpublishIds
|
|
922
|
-
}
|
|
923
|
-
},
|
|
924
|
-
populate
|
|
925
|
-
}
|
|
926
|
-
);
|
|
927
|
-
if (entriesToPublish.length > 0) {
|
|
928
|
-
await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
|
|
929
|
-
}
|
|
930
|
-
if (entriesToUnpublish.length > 0) {
|
|
931
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, contentTypeUid);
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
});
|
|
935
|
-
const release2 = await strapi2.entityService.update(RELEASE_MODEL_UID, releaseId, {
|
|
936
|
-
data: {
|
|
937
|
-
/*
|
|
938
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">> looks like it's wrong
|
|
939
|
-
*/
|
|
940
|
-
// @ts-expect-error see above
|
|
941
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
942
|
-
},
|
|
943
|
-
populate: {
|
|
944
|
-
actions: {
|
|
945
|
-
// @ts-expect-error is not expecting count but it is working
|
|
946
|
-
count: true
|
|
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()
|
|
947
836
|
}
|
|
948
|
-
}
|
|
949
|
-
});
|
|
950
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
837
|
+
});
|
|
951
838
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
952
839
|
isPublished: true,
|
|
953
|
-
release:
|
|
840
|
+
release: release22
|
|
954
841
|
});
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
} catch (error) {
|
|
959
|
-
if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
|
|
842
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
843
|
+
return { release: release22, error: null };
|
|
844
|
+
} catch (error2) {
|
|
960
845
|
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
961
846
|
isPublished: false,
|
|
962
|
-
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
|
+
}
|
|
963
887
|
});
|
|
964
888
|
}
|
|
965
|
-
strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
966
|
-
where: {
|
|
889
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
890
|
+
where: {
|
|
891
|
+
id: releaseId
|
|
892
|
+
},
|
|
967
893
|
data: {
|
|
968
|
-
status: "
|
|
894
|
+
status: "ready"
|
|
969
895
|
}
|
|
970
896
|
});
|
|
971
|
-
throw error;
|
|
972
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;
|
|
973
1081
|
},
|
|
974
|
-
async
|
|
975
|
-
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({
|
|
976
1088
|
where: {
|
|
977
1089
|
id: actionId,
|
|
978
1090
|
release: {
|
|
@@ -981,17 +1093,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
981
1093
|
$null: true
|
|
982
1094
|
}
|
|
983
1095
|
}
|
|
984
|
-
}
|
|
985
|
-
data: update
|
|
1096
|
+
}
|
|
986
1097
|
});
|
|
987
|
-
if (!
|
|
1098
|
+
if (!action) {
|
|
988
1099
|
throw new utils.errors.NotFoundError(
|
|
989
1100
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
990
1101
|
);
|
|
991
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);
|
|
992
1129
|
return updatedAction;
|
|
993
1130
|
},
|
|
994
|
-
async
|
|
1131
|
+
async delete(actionId, releaseId) {
|
|
995
1132
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
996
1133
|
where: {
|
|
997
1134
|
id: actionId,
|
|
@@ -1008,87 +1145,104 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1008
1145
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1009
1146
|
);
|
|
1010
1147
|
}
|
|
1011
|
-
|
|
1148
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1012
1149
|
return deletedAction;
|
|
1013
1150
|
},
|
|
1014
|
-
async
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
})
|
|
1027
|
-
]);
|
|
1028
|
-
if (totalActions > 0) {
|
|
1029
|
-
if (invalidActions > 0) {
|
|
1030
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1031
|
-
where: {
|
|
1032
|
-
id: releaseId
|
|
1033
|
-
},
|
|
1034
|
-
data: {
|
|
1035
|
-
status: "blocked"
|
|
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
|
|
1036
1162
|
}
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
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({
|
|
1040
1178
|
where: {
|
|
1041
|
-
id:
|
|
1179
|
+
id: action.id
|
|
1042
1180
|
},
|
|
1043
1181
|
data: {
|
|
1044
|
-
|
|
1182
|
+
isEntryValid: isValid
|
|
1045
1183
|
}
|
|
1046
1184
|
});
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
where: {
|
|
1050
|
-
id: releaseId
|
|
1051
|
-
},
|
|
1052
|
-
data: {
|
|
1053
|
-
status: "empty"
|
|
1185
|
+
if (!releasesUpdated.includes(action.release.id)) {
|
|
1186
|
+
releasesUpdated.push(action.release.id);
|
|
1054
1187
|
}
|
|
1188
|
+
return {
|
|
1189
|
+
id: action.id,
|
|
1190
|
+
isEntryValid: isValid
|
|
1191
|
+
};
|
|
1055
1192
|
});
|
|
1193
|
+
if (releasesUpdated.length > 0) {
|
|
1194
|
+
await utils.async.map(releasesUpdated, async (releaseId) => {
|
|
1195
|
+
await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1056
1198
|
}
|
|
1057
1199
|
};
|
|
1058
1200
|
};
|
|
1201
|
+
class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
1202
|
+
constructor(message) {
|
|
1203
|
+
super(message);
|
|
1204
|
+
this.name = "AlreadyOnReleaseError";
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1059
1207
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1060
1208
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1061
|
-
const release2 = await strapi2.
|
|
1062
|
-
|
|
1209
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1210
|
+
where: {
|
|
1211
|
+
id: releaseId
|
|
1212
|
+
},
|
|
1213
|
+
populate: {
|
|
1214
|
+
actions: true
|
|
1215
|
+
}
|
|
1063
1216
|
});
|
|
1064
1217
|
if (!release2) {
|
|
1065
1218
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1066
1219
|
}
|
|
1067
1220
|
const isEntryInRelease = release2.actions.some(
|
|
1068
|
-
(action) =>
|
|
1221
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1069
1222
|
);
|
|
1070
1223
|
if (isEntryInRelease) {
|
|
1071
|
-
throw new
|
|
1072
|
-
`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}`
|
|
1073
1226
|
);
|
|
1074
1227
|
}
|
|
1075
1228
|
},
|
|
1076
|
-
|
|
1229
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1077
1230
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1078
1231
|
if (!contentType) {
|
|
1079
1232
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1080
1233
|
}
|
|
1081
|
-
if (!contentType
|
|
1234
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1082
1235
|
throw new utils.errors.ValidationError(
|
|
1083
1236
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1084
1237
|
);
|
|
1085
1238
|
}
|
|
1239
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1240
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1241
|
+
}
|
|
1086
1242
|
},
|
|
1087
1243
|
async validatePendingReleasesLimit() {
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1091
|
-
);
|
|
1244
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1245
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1092
1246
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1093
1247
|
filters: {
|
|
1094
1248
|
releasedAt: {
|
|
@@ -1101,8 +1255,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1101
1255
|
}
|
|
1102
1256
|
},
|
|
1103
1257
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1104
|
-
const pendingReleases = await strapi2.
|
|
1105
|
-
|
|
1258
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1259
|
+
where: {
|
|
1106
1260
|
releasedAt: {
|
|
1107
1261
|
$null: true
|
|
1108
1262
|
},
|
|
@@ -1131,7 +1285,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1131
1285
|
}
|
|
1132
1286
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1133
1287
|
try {
|
|
1134
|
-
await getService("release").publish(releaseId);
|
|
1288
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1135
1289
|
} catch (error) {
|
|
1136
1290
|
}
|
|
1137
1291
|
this.cancel(releaseId);
|
|
@@ -1173,85 +1327,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1173
1327
|
}
|
|
1174
1328
|
};
|
|
1175
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
|
+
};
|
|
1176
1351
|
const services = {
|
|
1177
1352
|
release: createReleaseService,
|
|
1353
|
+
"release-action": createReleaseActionService,
|
|
1178
1354
|
"release-validation": createReleaseValidationService,
|
|
1179
|
-
|
|
1355
|
+
scheduling: createSchedulingService,
|
|
1356
|
+
settings: createSettingsService
|
|
1180
1357
|
};
|
|
1181
|
-
const RELEASE_SCHEMA =
|
|
1182
|
-
name:
|
|
1183
|
-
scheduledAt:
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
otherwise: yup__namespace.string().nullable()
|
|
1189
|
-
}),
|
|
1190
|
-
timezone: yup__namespace.string().when("isScheduled", {
|
|
1191
|
-
is: true,
|
|
1192
|
-
then: yup__namespace.string().required().nullable(),
|
|
1193
|
-
otherwise: yup__namespace.string().nullable()
|
|
1194
|
-
}),
|
|
1195
|
-
date: yup__namespace.string().when("isScheduled", {
|
|
1196
|
-
is: true,
|
|
1197
|
-
then: yup__namespace.string().required().nullable(),
|
|
1198
|
-
otherwise: yup__namespace.string().nullable()
|
|
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()
|
|
1199
1365
|
})
|
|
1200
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();
|
|
1201
1373
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1374
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1375
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1376
|
+
);
|
|
1202
1377
|
const releaseController = {
|
|
1203
|
-
|
|
1204
|
-
|
|
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({
|
|
1205
1385
|
ability: ctx.state.userAbility,
|
|
1206
1386
|
model: RELEASE_MODEL_UID
|
|
1207
1387
|
});
|
|
1208
1388
|
await permissionsManager.validateQuery(ctx.query);
|
|
1209
1389
|
const releaseService = getService("release", { strapi });
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
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,
|
|
1225
1406
|
actions: {
|
|
1226
|
-
|
|
1227
|
-
|
|
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
|
|
1228
1419
|
}
|
|
1229
1420
|
}
|
|
1230
|
-
}
|
|
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
|
+
}
|
|
1231
1434
|
});
|
|
1232
|
-
const
|
|
1435
|
+
const releases = await releaseService.findMany({
|
|
1233
1436
|
where: {
|
|
1437
|
+
$or: [
|
|
1438
|
+
{
|
|
1439
|
+
id: {
|
|
1440
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
{
|
|
1444
|
+
actions: null
|
|
1445
|
+
}
|
|
1446
|
+
],
|
|
1234
1447
|
releasedAt: null
|
|
1235
1448
|
}
|
|
1236
1449
|
});
|
|
1237
|
-
ctx.body = { data
|
|
1450
|
+
ctx.body = { data: releases };
|
|
1238
1451
|
}
|
|
1239
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
|
+
},
|
|
1240
1480
|
async findOne(ctx) {
|
|
1241
1481
|
const id = ctx.params.id;
|
|
1242
1482
|
const releaseService = getService("release", { strapi });
|
|
1483
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1243
1484
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1244
1485
|
if (!release2) {
|
|
1245
1486
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1246
1487
|
}
|
|
1247
|
-
const count = await
|
|
1488
|
+
const count = await releaseActionService.countActions({
|
|
1248
1489
|
filters: {
|
|
1249
1490
|
release: id
|
|
1250
1491
|
}
|
|
1251
1492
|
});
|
|
1252
1493
|
const sanitizedRelease = {
|
|
1253
1494
|
...release2,
|
|
1254
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1495
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1255
1496
|
};
|
|
1256
1497
|
const data = {
|
|
1257
1498
|
...sanitizedRelease,
|
|
@@ -1263,19 +1504,63 @@ const releaseController = {
|
|
|
1263
1504
|
};
|
|
1264
1505
|
ctx.body = { data };
|
|
1265
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
|
+
},
|
|
1266
1551
|
async create(ctx) {
|
|
1267
1552
|
const user = ctx.state.user;
|
|
1268
1553
|
const releaseArgs = ctx.request.body;
|
|
1269
1554
|
await validateRelease(releaseArgs);
|
|
1270
1555
|
const releaseService = getService("release", { strapi });
|
|
1271
1556
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1272
|
-
const permissionsManager = strapi.admin
|
|
1557
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1273
1558
|
ability: ctx.state.userAbility,
|
|
1274
1559
|
model: RELEASE_MODEL_UID
|
|
1275
1560
|
});
|
|
1276
|
-
ctx.
|
|
1561
|
+
ctx.created({
|
|
1277
1562
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1278
|
-
};
|
|
1563
|
+
});
|
|
1279
1564
|
},
|
|
1280
1565
|
async update(ctx) {
|
|
1281
1566
|
const user = ctx.state.user;
|
|
@@ -1284,7 +1569,7 @@ const releaseController = {
|
|
|
1284
1569
|
await validateRelease(releaseArgs);
|
|
1285
1570
|
const releaseService = getService("release", { strapi });
|
|
1286
1571
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1287
|
-
const permissionsManager = strapi.admin
|
|
1572
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1288
1573
|
ability: ctx.state.userAbility,
|
|
1289
1574
|
model: RELEASE_MODEL_UID
|
|
1290
1575
|
});
|
|
@@ -1301,18 +1586,18 @@ const releaseController = {
|
|
|
1301
1586
|
};
|
|
1302
1587
|
},
|
|
1303
1588
|
async publish(ctx) {
|
|
1304
|
-
const user = ctx.state.user;
|
|
1305
1589
|
const id = ctx.params.id;
|
|
1306
1590
|
const releaseService = getService("release", { strapi });
|
|
1307
|
-
const
|
|
1591
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1592
|
+
const release2 = await releaseService.publish(id);
|
|
1308
1593
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1309
|
-
|
|
1594
|
+
releaseActionService.countActions({
|
|
1310
1595
|
filters: {
|
|
1311
1596
|
release: id,
|
|
1312
1597
|
type: "publish"
|
|
1313
1598
|
}
|
|
1314
1599
|
}),
|
|
1315
|
-
|
|
1600
|
+
releaseActionService.countActions({
|
|
1316
1601
|
filters: {
|
|
1317
1602
|
release: id,
|
|
1318
1603
|
type: "unpublish"
|
|
@@ -1330,57 +1615,106 @@ const releaseController = {
|
|
|
1330
1615
|
}
|
|
1331
1616
|
};
|
|
1332
1617
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
}).required(),
|
|
1618
|
+
contentType: utils.yup.string().required(),
|
|
1619
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1620
|
+
locale: utils.yup.string(),
|
|
1337
1621
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1338
1622
|
});
|
|
1339
1623
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1340
1624
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1341
1625
|
});
|
|
1626
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1627
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1628
|
+
});
|
|
1342
1629
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1343
1630
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1631
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1344
1632
|
const releaseActionController = {
|
|
1345
1633
|
async create(ctx) {
|
|
1346
1634
|
const releaseId = ctx.params.releaseId;
|
|
1347
1635
|
const releaseActionArgs = ctx.request.body;
|
|
1348
1636
|
await validateReleaseAction(releaseActionArgs);
|
|
1349
|
-
const
|
|
1350
|
-
const releaseAction2 = await
|
|
1351
|
-
ctx.
|
|
1637
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1638
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1639
|
+
ctx.created({
|
|
1352
1640
|
data: releaseAction2
|
|
1353
|
-
};
|
|
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
|
+
});
|
|
1354
1680
|
},
|
|
1355
1681
|
async findMany(ctx) {
|
|
1356
1682
|
const releaseId = ctx.params.releaseId;
|
|
1357
|
-
const permissionsManager = strapi.admin
|
|
1683
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1358
1684
|
ability: ctx.state.userAbility,
|
|
1359
1685
|
model: RELEASE_ACTION_MODEL_UID
|
|
1360
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;
|
|
1361
1695
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1362
|
-
const
|
|
1363
|
-
const { results, pagination } = await
|
|
1364
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1696
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1697
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1365
1698
|
...query
|
|
1366
1699
|
});
|
|
1367
1700
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1368
1701
|
if (acc[action.contentType]) {
|
|
1369
1702
|
return acc;
|
|
1370
1703
|
}
|
|
1371
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1704
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1372
1705
|
ability: ctx.state.userAbility,
|
|
1373
1706
|
model: action.contentType
|
|
1374
1707
|
});
|
|
1375
1708
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1376
1709
|
return acc;
|
|
1377
1710
|
}, {});
|
|
1378
|
-
const sanitizedResults = await utils.
|
|
1711
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1379
1712
|
...action,
|
|
1380
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1713
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1381
1714
|
}));
|
|
1382
|
-
const groupedData = await
|
|
1383
|
-
const contentTypes2 =
|
|
1715
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1716
|
+
const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
|
|
1717
|
+
const releaseService = getService("release", { strapi });
|
|
1384
1718
|
const components = await releaseService.getAllComponents();
|
|
1385
1719
|
ctx.body = {
|
|
1386
1720
|
data: groupedData,
|
|
@@ -1396,8 +1730,8 @@ const releaseActionController = {
|
|
|
1396
1730
|
const releaseId = ctx.params.releaseId;
|
|
1397
1731
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1398
1732
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1399
|
-
const
|
|
1400
|
-
const updatedAction = await
|
|
1733
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1734
|
+
const updatedAction = await releaseActionService.update(
|
|
1401
1735
|
actionId,
|
|
1402
1736
|
releaseId,
|
|
1403
1737
|
releaseActionUpdateArgs
|
|
@@ -1409,17 +1743,71 @@ const releaseActionController = {
|
|
|
1409
1743
|
async delete(ctx) {
|
|
1410
1744
|
const actionId = ctx.params.actionId;
|
|
1411
1745
|
const releaseId = ctx.params.releaseId;
|
|
1412
|
-
const
|
|
1413
|
-
const deletedReleaseAction = await
|
|
1746
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1747
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1414
1748
|
ctx.body = {
|
|
1415
1749
|
data: deletedReleaseAction
|
|
1416
1750
|
};
|
|
1417
1751
|
}
|
|
1418
1752
|
};
|
|
1419
|
-
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
|
+
};
|
|
1420
1776
|
const release = {
|
|
1421
1777
|
type: "admin",
|
|
1422
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
|
+
},
|
|
1423
1811
|
{
|
|
1424
1812
|
method: "POST",
|
|
1425
1813
|
path: "/",
|
|
@@ -1439,7 +1827,7 @@ const release = {
|
|
|
1439
1827
|
{
|
|
1440
1828
|
method: "GET",
|
|
1441
1829
|
path: "/",
|
|
1442
|
-
handler: "release.
|
|
1830
|
+
handler: "release.findPage",
|
|
1443
1831
|
config: {
|
|
1444
1832
|
policies: [
|
|
1445
1833
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1537,6 +1925,22 @@ const releaseAction = {
|
|
|
1537
1925
|
]
|
|
1538
1926
|
}
|
|
1539
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
|
+
},
|
|
1540
1944
|
{
|
|
1541
1945
|
method: "GET",
|
|
1542
1946
|
path: "/:releaseId/actions",
|
|
@@ -1587,13 +1991,50 @@ const releaseAction = {
|
|
|
1587
1991
|
}
|
|
1588
1992
|
]
|
|
1589
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
|
+
};
|
|
1590
2031
|
const routes = {
|
|
2032
|
+
settings,
|
|
1591
2033
|
release,
|
|
1592
2034
|
"release-action": releaseAction
|
|
1593
2035
|
};
|
|
1594
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1595
2036
|
const getPlugin = () => {
|
|
1596
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
2037
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1597
2038
|
return {
|
|
1598
2039
|
register,
|
|
1599
2040
|
bootstrap,
|
|
@@ -1605,6 +2046,9 @@ const getPlugin = () => {
|
|
|
1605
2046
|
};
|
|
1606
2047
|
}
|
|
1607
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
|
|
1608
2052
|
contentTypes
|
|
1609
2053
|
};
|
|
1610
2054
|
};
|