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