@strapi/content-releases 0.0.0-next.d0bd7aa4c25bfb448b93a62f3d47db9b6fdd8ee3 → 0.0.0-next.d2d15ef227d67cce89c2673764c0555c841cd29c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -1
- package/dist/_chunks/App-BA2xDdy0.mjs +1374 -0
- package/dist/_chunks/App-BA2xDdy0.mjs.map +1 -0
- package/dist/_chunks/App-D4Wira1X.js +1395 -0
- package/dist/_chunks/App-D4Wira1X.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
- package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-BAlbMWpw.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-BAlbMWpw.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-xhFyRXCM.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-xhFyRXCM.js.map +1 -0
- package/dist/_chunks/{en-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-CCFFG3Zs.mjs +1365 -0
- package/dist/_chunks/index-CCFFG3Zs.mjs.map +1 -0
- package/dist/_chunks/index-DxkQGp4N.js +1384 -0
- package/dist/_chunks/index-DxkQGp4N.js.map +1 -0
- package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
- package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
- package/dist/admin/index.js +1 -15
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +2 -16
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/RelativeTime.d.ts +28 -0
- package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
- package/dist/admin/src/components/ReleaseActionModal.d.ts +24 -0
- package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
- package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
- package/dist/admin/src/components/ReleaseModal.d.ts +17 -0
- package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
- package/dist/admin/src/constants.d.ts +76 -0
- package/dist/admin/src/index.d.ts +3 -0
- package/dist/admin/src/modules/hooks.d.ts +7 -0
- package/dist/admin/src/pages/App.d.ts +1 -0
- package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
- package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
- package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
- package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
- package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
- package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/services/release.d.ts +112 -0
- package/dist/admin/src/store/hooks.d.ts +7 -0
- package/dist/admin/src/utils/api.d.ts +6 -0
- package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
- package/dist/admin/src/utils/time.d.ts +10 -0
- package/dist/admin/src/validation/schemas.d.ts +6 -0
- package/dist/server/index.js +878 -617
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +879 -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 +32 -37
- package/dist/_chunks/App-HVXzE3i3.mjs +0 -1313
- package/dist/_chunks/App-HVXzE3i3.mjs.map +0 -1
- package/dist/_chunks/App-l62gIUTX.js +0 -1336
- package/dist/_chunks/App-l62gIUTX.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-ML_b3php.js +0 -1034
- package/dist/_chunks/index-ML_b3php.js.map +0 -1
- package/dist/_chunks/index-Ys87ROOe.mjs +0 -1013
- package/dist/_chunks/index-Ys87ROOe.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,39 @@ 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 hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
310
|
+
if (hasPolymorphicColumn) {
|
|
311
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
312
|
+
"strapi_release_actions",
|
|
313
|
+
"entry_document_id"
|
|
314
|
+
);
|
|
315
|
+
if (!hasEntryDocumentIdColumn) {
|
|
316
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
317
|
+
table.string("entry_document_id");
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
321
|
+
async.map(releaseActions, async (action) => {
|
|
322
|
+
const { target_type, target_id } = action;
|
|
323
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
324
|
+
if (entry) {
|
|
325
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
async down() {
|
|
331
|
+
throw new Error("not implemented");
|
|
332
|
+
}
|
|
333
|
+
};
|
|
251
334
|
const register = async ({ strapi: strapi2 }) => {
|
|
252
|
-
if (features
|
|
253
|
-
await strapi2.admin
|
|
254
|
-
strapi2.
|
|
335
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
336
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
337
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
338
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
255
339
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
256
340
|
}
|
|
257
341
|
if (strapi2.plugin("graphql")) {
|
|
@@ -260,129 +344,134 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
260
344
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
261
345
|
}
|
|
262
346
|
};
|
|
263
|
-
const
|
|
347
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
348
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
349
|
+
where: {
|
|
350
|
+
actions: {
|
|
351
|
+
contentType,
|
|
352
|
+
entryDocumentId: entry.documentId,
|
|
353
|
+
locale: entry.locale
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
358
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
359
|
+
where: {
|
|
360
|
+
contentType,
|
|
361
|
+
entryDocumentId: entry.documentId,
|
|
362
|
+
locale: entry.locale
|
|
363
|
+
},
|
|
364
|
+
data: {
|
|
365
|
+
isEntryValid: entryStatus
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
for (const release2 of releases) {
|
|
369
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
373
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
374
|
+
where: {
|
|
375
|
+
actions: params
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
379
|
+
where: params
|
|
380
|
+
});
|
|
381
|
+
for (const release2 of releases) {
|
|
382
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
386
|
+
if (ctx.action !== "delete") {
|
|
387
|
+
return next();
|
|
388
|
+
}
|
|
389
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
390
|
+
return next();
|
|
391
|
+
}
|
|
392
|
+
const contentType = ctx.contentType.uid;
|
|
393
|
+
const { documentId, locale } = ctx.params;
|
|
394
|
+
const result = await next();
|
|
395
|
+
if (!result) {
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
400
|
+
contentType,
|
|
401
|
+
entryDocumentId: documentId,
|
|
402
|
+
...locale !== "*" && { locale }
|
|
403
|
+
});
|
|
404
|
+
} catch (error) {
|
|
405
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
406
|
+
error
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
};
|
|
411
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
412
|
+
if (ctx.action !== "update") {
|
|
413
|
+
return next();
|
|
414
|
+
}
|
|
415
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
416
|
+
return next();
|
|
417
|
+
}
|
|
418
|
+
const contentType = ctx.contentType.uid;
|
|
419
|
+
const result = await next();
|
|
420
|
+
if (!result) {
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
427
|
+
error
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return result;
|
|
431
|
+
};
|
|
432
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
433
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
434
|
+
where: {
|
|
435
|
+
actions: params
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
439
|
+
where: params
|
|
440
|
+
});
|
|
441
|
+
for (const release2 of releases) {
|
|
442
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
264
445
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
265
|
-
if (features
|
|
446
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
266
447
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
267
448
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
268
449
|
);
|
|
269
450
|
strapi2.db.lifecycles.subscribe({
|
|
270
451
|
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
|
-
/**
|
|
299
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
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
452
|
/**
|
|
311
|
-
*
|
|
312
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
453
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
313
454
|
*/
|
|
314
455
|
async afterDeleteMany(event) {
|
|
315
456
|
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
|
-
}
|
|
457
|
+
const model = strapi2.getModel(event.model.uid);
|
|
458
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
459
|
+
const { where } = event.params;
|
|
460
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
461
|
+
contentType: model.uid,
|
|
462
|
+
locale: where.locale ?? null,
|
|
463
|
+
...where.documentId && { entryDocumentId: where.documentId }
|
|
338
464
|
});
|
|
339
|
-
for (const release2 of releases) {
|
|
340
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
341
|
-
}
|
|
342
465
|
}
|
|
343
466
|
} catch (error) {
|
|
344
467
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
345
468
|
error
|
|
346
469
|
});
|
|
347
470
|
}
|
|
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
471
|
}
|
|
385
472
|
});
|
|
473
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
474
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
386
475
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
387
476
|
strapi2.log.error(
|
|
388
477
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -390,7 +479,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
390
479
|
throw err;
|
|
391
480
|
});
|
|
392
481
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
393
|
-
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
482
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
394
483
|
});
|
|
395
484
|
}
|
|
396
485
|
};
|
|
@@ -474,15 +563,13 @@ const schema = {
|
|
|
474
563
|
enum: ["publish", "unpublish"],
|
|
475
564
|
required: true
|
|
476
565
|
},
|
|
477
|
-
entry: {
|
|
478
|
-
type: "relation",
|
|
479
|
-
relation: "morphToOne",
|
|
480
|
-
configurable: false
|
|
481
|
-
},
|
|
482
566
|
contentType: {
|
|
483
567
|
type: "string",
|
|
484
568
|
required: true
|
|
485
569
|
},
|
|
570
|
+
entryDocumentId: {
|
|
571
|
+
type: "string"
|
|
572
|
+
},
|
|
486
573
|
locale: {
|
|
487
574
|
type: "string"
|
|
488
575
|
},
|
|
@@ -504,18 +591,6 @@ const contentTypes = {
|
|
|
504
591
|
release: release$1,
|
|
505
592
|
"release-action": releaseAction$1
|
|
506
593
|
};
|
|
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
594
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
520
595
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
521
596
|
strapi2.eventHub.emit(event, {
|
|
@@ -524,93 +599,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
524
599
|
release: release2
|
|
525
600
|
});
|
|
526
601
|
};
|
|
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
602
|
const getFormattedActions = async (releaseId) => {
|
|
574
603
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
575
604
|
where: {
|
|
576
605
|
release: {
|
|
577
606
|
id: releaseId
|
|
578
607
|
}
|
|
579
|
-
},
|
|
580
|
-
populate: {
|
|
581
|
-
entry: {
|
|
582
|
-
fields: ["id"]
|
|
583
|
-
}
|
|
584
608
|
}
|
|
585
609
|
});
|
|
586
610
|
if (actions.length === 0) {
|
|
587
611
|
throw new errors.ValidationError("No entries to publish");
|
|
588
612
|
}
|
|
589
|
-
const
|
|
590
|
-
const singleTypeActions = [];
|
|
613
|
+
const formattedActions = {};
|
|
591
614
|
for (const action of actions) {
|
|
592
615
|
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
|
-
});
|
|
616
|
+
if (!formattedActions[contentTypeUid]) {
|
|
617
|
+
formattedActions[contentTypeUid] = {
|
|
618
|
+
publish: [],
|
|
619
|
+
unpublish: []
|
|
620
|
+
};
|
|
611
621
|
}
|
|
622
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
623
|
+
documentId: action.entryDocumentId,
|
|
624
|
+
locale: action.locale
|
|
625
|
+
});
|
|
612
626
|
}
|
|
613
|
-
return
|
|
627
|
+
return formattedActions;
|
|
614
628
|
};
|
|
615
629
|
return {
|
|
616
630
|
async create(releaseData, { user }) {
|
|
@@ -625,7 +639,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
625
639
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
626
640
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
627
641
|
]);
|
|
628
|
-
const release2 = await strapi2.
|
|
642
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
629
643
|
data: {
|
|
630
644
|
...releaseWithCreatorFields,
|
|
631
645
|
status: "empty"
|
|
@@ -639,94 +653,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
639
653
|
return release2;
|
|
640
654
|
},
|
|
641
655
|
async findOne(id, query = {}) {
|
|
642
|
-
const
|
|
643
|
-
|
|
656
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
657
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
658
|
+
...dbQuery,
|
|
659
|
+
where: { id }
|
|
644
660
|
});
|
|
645
661
|
return release2;
|
|
646
662
|
},
|
|
647
663
|
findPage(query) {
|
|
648
|
-
|
|
649
|
-
|
|
664
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
665
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
666
|
+
...dbQuery,
|
|
650
667
|
populate: {
|
|
651
668
|
actions: {
|
|
652
|
-
// @ts-expect-error Ignore missing properties
|
|
653
669
|
count: true
|
|
654
670
|
}
|
|
655
671
|
}
|
|
656
672
|
});
|
|
657
673
|
},
|
|
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;
|
|
674
|
+
findMany(query) {
|
|
675
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
676
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
677
|
+
...dbQuery
|
|
730
678
|
});
|
|
731
679
|
},
|
|
732
680
|
async update(id, releaseData, { user }) {
|
|
@@ -741,19 +689,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
741
689
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
742
690
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
743
691
|
]);
|
|
744
|
-
const release2 = await strapi2.
|
|
692
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
745
693
|
if (!release2) {
|
|
746
694
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
747
695
|
}
|
|
748
696
|
if (release2.releasedAt) {
|
|
749
697
|
throw new errors.ValidationError("Release already published");
|
|
750
698
|
}
|
|
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
|
|
699
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
700
|
+
where: { id },
|
|
757
701
|
data: releaseWithCreatorFields
|
|
758
702
|
});
|
|
759
703
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -766,130 +710,6 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
766
710
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
767
711
|
return updatedRelease;
|
|
768
712
|
},
|
|
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
713
|
async getAllComponents() {
|
|
894
714
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
895
715
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -903,10 +723,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
903
723
|
return componentsMap;
|
|
904
724
|
},
|
|
905
725
|
async delete(releaseId) {
|
|
906
|
-
const release2 = await strapi2.
|
|
726
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
727
|
+
where: { id: releaseId },
|
|
907
728
|
populate: {
|
|
908
729
|
actions: {
|
|
909
|
-
|
|
730
|
+
select: ["id"]
|
|
910
731
|
}
|
|
911
732
|
}
|
|
912
733
|
});
|
|
@@ -924,7 +745,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
924
745
|
}
|
|
925
746
|
}
|
|
926
747
|
});
|
|
927
|
-
await strapi2.
|
|
748
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
749
|
+
where: {
|
|
750
|
+
id: releaseId
|
|
751
|
+
}
|
|
752
|
+
});
|
|
928
753
|
});
|
|
929
754
|
if (release2.scheduledAt) {
|
|
930
755
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -950,22 +775,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
950
775
|
}
|
|
951
776
|
try {
|
|
952
777
|
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
953
|
-
const
|
|
954
|
-
|
|
778
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
779
|
+
await strapi2.db.transaction(
|
|
780
|
+
async () => Promise.all(
|
|
781
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
782
|
+
const contentType = contentTypeUid;
|
|
783
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
784
|
+
return Promise.all([
|
|
785
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
786
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
787
|
+
]);
|
|
788
|
+
})
|
|
789
|
+
)
|
|
955
790
|
);
|
|
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
791
|
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
970
792
|
where: {
|
|
971
793
|
id: releaseId
|
|
@@ -995,13 +817,226 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
995
817
|
};
|
|
996
818
|
}
|
|
997
819
|
});
|
|
998
|
-
if (error) {
|
|
999
|
-
throw error;
|
|
1000
|
-
}
|
|
1001
|
-
return release2;
|
|
820
|
+
if (error instanceof Error) {
|
|
821
|
+
throw error;
|
|
822
|
+
}
|
|
823
|
+
return release2;
|
|
824
|
+
},
|
|
825
|
+
async updateReleaseStatus(releaseId) {
|
|
826
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
827
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
828
|
+
releaseActionService.countActions({
|
|
829
|
+
filters: {
|
|
830
|
+
release: releaseId
|
|
831
|
+
}
|
|
832
|
+
}),
|
|
833
|
+
releaseActionService.countActions({
|
|
834
|
+
filters: {
|
|
835
|
+
release: releaseId,
|
|
836
|
+
isEntryValid: false
|
|
837
|
+
}
|
|
838
|
+
})
|
|
839
|
+
]);
|
|
840
|
+
if (totalActions > 0) {
|
|
841
|
+
if (invalidActions > 0) {
|
|
842
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
843
|
+
where: {
|
|
844
|
+
id: releaseId
|
|
845
|
+
},
|
|
846
|
+
data: {
|
|
847
|
+
status: "blocked"
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
852
|
+
where: {
|
|
853
|
+
id: releaseId
|
|
854
|
+
},
|
|
855
|
+
data: {
|
|
856
|
+
status: "ready"
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
861
|
+
where: {
|
|
862
|
+
id: releaseId
|
|
863
|
+
},
|
|
864
|
+
data: {
|
|
865
|
+
status: "empty"
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
};
|
|
871
|
+
const getGroupName = (queryValue) => {
|
|
872
|
+
switch (queryValue) {
|
|
873
|
+
case "contentType":
|
|
874
|
+
return "contentType.displayName";
|
|
875
|
+
case "type":
|
|
876
|
+
return "type";
|
|
877
|
+
case "locale":
|
|
878
|
+
return _.getOr("No locale", "locale.name");
|
|
879
|
+
default:
|
|
880
|
+
return "contentType.displayName";
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
884
|
+
const getLocalesDataForActions = async () => {
|
|
885
|
+
if (!strapi2.plugin("i18n")) {
|
|
886
|
+
return {};
|
|
887
|
+
}
|
|
888
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
889
|
+
return allLocales.reduce((acc, locale) => {
|
|
890
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
891
|
+
return acc;
|
|
892
|
+
}, {});
|
|
893
|
+
};
|
|
894
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
895
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
896
|
+
const contentTypesData = {};
|
|
897
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
898
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
899
|
+
uid: contentTypeUid
|
|
900
|
+
});
|
|
901
|
+
contentTypesData[contentTypeUid] = {
|
|
902
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
903
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
return contentTypesData;
|
|
907
|
+
};
|
|
908
|
+
return {
|
|
909
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
910
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
911
|
+
strapi: strapi2
|
|
912
|
+
});
|
|
913
|
+
await Promise.all([
|
|
914
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
915
|
+
validateUniqueEntry(releaseId, action)
|
|
916
|
+
]);
|
|
917
|
+
const model = strapi2.contentType(action.contentType);
|
|
918
|
+
if (model.kind === "singleType") {
|
|
919
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
920
|
+
if (!document) {
|
|
921
|
+
throw new errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
922
|
+
}
|
|
923
|
+
action.entryDocumentId = document.documentId;
|
|
924
|
+
}
|
|
925
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
926
|
+
if (!release2) {
|
|
927
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
928
|
+
}
|
|
929
|
+
if (release2.releasedAt) {
|
|
930
|
+
throw new errors.ValidationError("Release already published");
|
|
931
|
+
}
|
|
932
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
933
|
+
{
|
|
934
|
+
contentType: action.contentType,
|
|
935
|
+
documentId: action.entryDocumentId,
|
|
936
|
+
locale: action.locale
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
strapi: strapi2
|
|
940
|
+
}
|
|
941
|
+
) : true;
|
|
942
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
943
|
+
data: {
|
|
944
|
+
...action,
|
|
945
|
+
release: release2.id,
|
|
946
|
+
isEntryValid: actionStatus
|
|
947
|
+
},
|
|
948
|
+
populate: { release: { select: ["id"] } }
|
|
949
|
+
});
|
|
950
|
+
if (!disableUpdateReleaseStatus) {
|
|
951
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
952
|
+
}
|
|
953
|
+
return releaseAction2;
|
|
954
|
+
},
|
|
955
|
+
async findPage(releaseId, query) {
|
|
956
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
957
|
+
where: { id: releaseId },
|
|
958
|
+
select: ["id"]
|
|
959
|
+
});
|
|
960
|
+
if (!release2) {
|
|
961
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
962
|
+
}
|
|
963
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
964
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
965
|
+
...dbQuery,
|
|
966
|
+
where: {
|
|
967
|
+
release: releaseId
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
971
|
+
const actionsWithEntry = await async.map(actions, async (action) => {
|
|
972
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
973
|
+
const entry = await getEntry(
|
|
974
|
+
{
|
|
975
|
+
contentType: action.contentType,
|
|
976
|
+
documentId: action.entryDocumentId,
|
|
977
|
+
locale: action.locale,
|
|
978
|
+
populate,
|
|
979
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
980
|
+
},
|
|
981
|
+
{ strapi: strapi2 }
|
|
982
|
+
);
|
|
983
|
+
return {
|
|
984
|
+
...action,
|
|
985
|
+
entry,
|
|
986
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
987
|
+
};
|
|
988
|
+
});
|
|
989
|
+
return {
|
|
990
|
+
results: actionsWithEntry,
|
|
991
|
+
pagination
|
|
992
|
+
};
|
|
993
|
+
},
|
|
994
|
+
async groupActions(actions, groupBy) {
|
|
995
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
996
|
+
if (!acc.includes(action.contentType)) {
|
|
997
|
+
acc.push(action.contentType);
|
|
998
|
+
}
|
|
999
|
+
return acc;
|
|
1000
|
+
}, []);
|
|
1001
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1002
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1003
|
+
const formattedData = actions.map((action) => {
|
|
1004
|
+
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1005
|
+
return {
|
|
1006
|
+
...action,
|
|
1007
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1008
|
+
contentType: {
|
|
1009
|
+
displayName,
|
|
1010
|
+
mainFieldValue: action.entry[mainField],
|
|
1011
|
+
uid: action.contentType
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
});
|
|
1015
|
+
const groupName = getGroupName(groupBy);
|
|
1016
|
+
return _.groupBy(groupName)(formattedData);
|
|
1002
1017
|
},
|
|
1003
|
-
|
|
1004
|
-
const
|
|
1018
|
+
getContentTypeModelsFromActions(actions) {
|
|
1019
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1020
|
+
if (!acc.includes(action.contentType)) {
|
|
1021
|
+
acc.push(action.contentType);
|
|
1022
|
+
}
|
|
1023
|
+
return acc;
|
|
1024
|
+
}, []);
|
|
1025
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1026
|
+
(acc, contentTypeUid) => {
|
|
1027
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1028
|
+
return acc;
|
|
1029
|
+
},
|
|
1030
|
+
{}
|
|
1031
|
+
);
|
|
1032
|
+
return contentTypeModelsMap;
|
|
1033
|
+
},
|
|
1034
|
+
async countActions(query) {
|
|
1035
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1036
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1037
|
+
},
|
|
1038
|
+
async update(actionId, releaseId, update) {
|
|
1039
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1005
1040
|
where: {
|
|
1006
1041
|
id: actionId,
|
|
1007
1042
|
release: {
|
|
@@ -1010,17 +1045,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1010
1045
|
$null: true
|
|
1011
1046
|
}
|
|
1012
1047
|
}
|
|
1013
|
-
}
|
|
1014
|
-
data: update
|
|
1048
|
+
}
|
|
1015
1049
|
});
|
|
1016
|
-
if (!
|
|
1050
|
+
if (!action) {
|
|
1017
1051
|
throw new errors.NotFoundError(
|
|
1018
1052
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1019
1053
|
);
|
|
1020
1054
|
}
|
|
1055
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1056
|
+
{
|
|
1057
|
+
contentType: action.contentType,
|
|
1058
|
+
documentId: action.entryDocumentId,
|
|
1059
|
+
locale: action.locale
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
strapi: strapi2
|
|
1063
|
+
}
|
|
1064
|
+
) : true;
|
|
1065
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1066
|
+
where: {
|
|
1067
|
+
id: actionId,
|
|
1068
|
+
release: {
|
|
1069
|
+
id: releaseId,
|
|
1070
|
+
releasedAt: {
|
|
1071
|
+
$null: true
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
data: {
|
|
1076
|
+
...update,
|
|
1077
|
+
isEntryValid: actionStatus
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1021
1081
|
return updatedAction;
|
|
1022
1082
|
},
|
|
1023
|
-
async
|
|
1083
|
+
async delete(actionId, releaseId) {
|
|
1024
1084
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1025
1085
|
where: {
|
|
1026
1086
|
id: actionId,
|
|
@@ -1037,51 +1097,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1037
1097
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1038
1098
|
);
|
|
1039
1099
|
}
|
|
1040
|
-
|
|
1100
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1041
1101
|
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
1102
|
}
|
|
1086
1103
|
};
|
|
1087
1104
|
};
|
|
@@ -1093,37 +1110,43 @@ class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
|
1093
1110
|
}
|
|
1094
1111
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1095
1112
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1096
|
-
const release2 = await strapi2.
|
|
1097
|
-
|
|
1113
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1114
|
+
where: {
|
|
1115
|
+
id: releaseId
|
|
1116
|
+
},
|
|
1117
|
+
populate: {
|
|
1118
|
+
actions: true
|
|
1119
|
+
}
|
|
1098
1120
|
});
|
|
1099
1121
|
if (!release2) {
|
|
1100
1122
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1101
1123
|
}
|
|
1102
1124
|
const isEntryInRelease = release2.actions.some(
|
|
1103
|
-
(action) =>
|
|
1125
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1104
1126
|
);
|
|
1105
1127
|
if (isEntryInRelease) {
|
|
1106
1128
|
throw new AlreadyOnReleaseError(
|
|
1107
|
-
`Entry with
|
|
1129
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1108
1130
|
);
|
|
1109
1131
|
}
|
|
1110
1132
|
},
|
|
1111
|
-
|
|
1133
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1112
1134
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1113
1135
|
if (!contentType) {
|
|
1114
1136
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1115
1137
|
}
|
|
1116
|
-
if (!contentType
|
|
1138
|
+
if (!contentTypes$1.hasDraftAndPublish(contentType)) {
|
|
1117
1139
|
throw new errors.ValidationError(
|
|
1118
1140
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1119
1141
|
);
|
|
1120
1142
|
}
|
|
1143
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1144
|
+
throw new errors.ValidationError("Document id is required for collection type");
|
|
1145
|
+
}
|
|
1121
1146
|
},
|
|
1122
1147
|
async validatePendingReleasesLimit() {
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1126
|
-
);
|
|
1148
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1149
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1127
1150
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1128
1151
|
filters: {
|
|
1129
1152
|
releasedAt: {
|
|
@@ -1136,8 +1159,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1136
1159
|
}
|
|
1137
1160
|
},
|
|
1138
1161
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1139
|
-
const pendingReleases = await strapi2.
|
|
1140
|
-
|
|
1162
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1163
|
+
where: {
|
|
1141
1164
|
releasedAt: {
|
|
1142
1165
|
$null: true
|
|
1143
1166
|
},
|
|
@@ -1166,7 +1189,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1166
1189
|
}
|
|
1167
1190
|
const job = scheduleJob(scheduleDate, async () => {
|
|
1168
1191
|
try {
|
|
1169
|
-
await getService("release").publish(releaseId);
|
|
1192
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1170
1193
|
} catch (error) {
|
|
1171
1194
|
}
|
|
1172
1195
|
this.cancel(releaseId);
|
|
@@ -1208,85 +1231,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1208
1231
|
}
|
|
1209
1232
|
};
|
|
1210
1233
|
};
|
|
1234
|
+
const DEFAULT_SETTINGS = {
|
|
1235
|
+
defaultTimezone: null
|
|
1236
|
+
};
|
|
1237
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1238
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1239
|
+
return {
|
|
1240
|
+
async update({ settings: settings2 }) {
|
|
1241
|
+
const store = await getStore();
|
|
1242
|
+
store.set({ key: "settings", value: settings2 });
|
|
1243
|
+
return settings2;
|
|
1244
|
+
},
|
|
1245
|
+
async find() {
|
|
1246
|
+
const store = await getStore();
|
|
1247
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1248
|
+
return {
|
|
1249
|
+
...DEFAULT_SETTINGS,
|
|
1250
|
+
...settings2 || {}
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
};
|
|
1211
1255
|
const services = {
|
|
1212
1256
|
release: createReleaseService,
|
|
1257
|
+
"release-action": createReleaseActionService,
|
|
1213
1258
|
"release-validation": createReleaseValidationService,
|
|
1214
|
-
scheduling: createSchedulingService
|
|
1259
|
+
scheduling: createSchedulingService,
|
|
1260
|
+
settings: createSettingsService
|
|
1215
1261
|
};
|
|
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()
|
|
1262
|
+
const RELEASE_SCHEMA = yup$1.object().shape({
|
|
1263
|
+
name: yup$1.string().trim().required(),
|
|
1264
|
+
scheduledAt: yup$1.string().nullable(),
|
|
1265
|
+
timezone: yup$1.string().when("scheduledAt", {
|
|
1266
|
+
is: (value) => value !== null && value !== void 0,
|
|
1267
|
+
then: yup$1.string().required(),
|
|
1268
|
+
otherwise: yup$1.string().nullable()
|
|
1234
1269
|
})
|
|
1235
1270
|
}).required().noUnknown();
|
|
1271
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = yup$1.object().shape({
|
|
1272
|
+
contentType: yup$1.string().required(),
|
|
1273
|
+
entryDocumentId: yup$1.string().nullable(),
|
|
1274
|
+
hasEntryAttached: yup$1.string().nullable(),
|
|
1275
|
+
locale: yup$1.string().nullable()
|
|
1276
|
+
}).required().noUnknown();
|
|
1236
1277
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
1278
|
+
const validatefindByDocumentAttachedParams = validateYupSchema(
|
|
1279
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1280
|
+
);
|
|
1237
1281
|
const releaseController = {
|
|
1238
|
-
|
|
1239
|
-
|
|
1282
|
+
/**
|
|
1283
|
+
* Find releases based on documents attached or not to the release.
|
|
1284
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1285
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1286
|
+
*/
|
|
1287
|
+
async findByDocumentAttached(ctx) {
|
|
1288
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1240
1289
|
ability: ctx.state.userAbility,
|
|
1241
1290
|
model: RELEASE_MODEL_UID
|
|
1242
1291
|
});
|
|
1243
1292
|
await permissionsManager.validateQuery(ctx.query);
|
|
1244
1293
|
const releaseService = getService("release", { strapi });
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1294
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1295
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1296
|
+
const model = strapi.getModel(query.contentType);
|
|
1297
|
+
if (model.kind && model.kind === "singleType") {
|
|
1298
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1299
|
+
if (!document) {
|
|
1300
|
+
throw new errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1301
|
+
}
|
|
1302
|
+
query.entryDocumentId = document.documentId;
|
|
1303
|
+
}
|
|
1304
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1305
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1306
|
+
if (isEntryAttached) {
|
|
1307
|
+
const releases = await releaseService.findMany({
|
|
1308
|
+
where: {
|
|
1309
|
+
releasedAt: null,
|
|
1310
|
+
actions: {
|
|
1311
|
+
contentType,
|
|
1312
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1313
|
+
locale: locale ?? null
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1316
|
+
populate: {
|
|
1260
1317
|
actions: {
|
|
1261
|
-
|
|
1262
|
-
|
|
1318
|
+
fields: ["type"],
|
|
1319
|
+
filters: {
|
|
1320
|
+
contentType,
|
|
1321
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1322
|
+
locale: locale ?? null
|
|
1263
1323
|
}
|
|
1264
1324
|
}
|
|
1265
|
-
}
|
|
1325
|
+
}
|
|
1326
|
+
});
|
|
1327
|
+
ctx.body = { data: releases };
|
|
1328
|
+
} else {
|
|
1329
|
+
const relatedReleases = await releaseService.findMany({
|
|
1330
|
+
where: {
|
|
1331
|
+
releasedAt: null,
|
|
1332
|
+
actions: {
|
|
1333
|
+
contentType,
|
|
1334
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1335
|
+
locale: locale ?? null
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1266
1338
|
});
|
|
1267
|
-
const
|
|
1339
|
+
const releases = await releaseService.findMany({
|
|
1268
1340
|
where: {
|
|
1341
|
+
$or: [
|
|
1342
|
+
{
|
|
1343
|
+
id: {
|
|
1344
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
actions: null
|
|
1349
|
+
}
|
|
1350
|
+
],
|
|
1269
1351
|
releasedAt: null
|
|
1270
1352
|
}
|
|
1271
1353
|
});
|
|
1272
|
-
ctx.body = { data
|
|
1354
|
+
ctx.body = { data: releases };
|
|
1273
1355
|
}
|
|
1274
1356
|
},
|
|
1357
|
+
async findPage(ctx) {
|
|
1358
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1359
|
+
ability: ctx.state.userAbility,
|
|
1360
|
+
model: RELEASE_MODEL_UID
|
|
1361
|
+
});
|
|
1362
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1363
|
+
const releaseService = getService("release", { strapi });
|
|
1364
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1365
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1366
|
+
const data = results.map((release2) => {
|
|
1367
|
+
const { actions, ...releaseData } = release2;
|
|
1368
|
+
return {
|
|
1369
|
+
...releaseData,
|
|
1370
|
+
actions: {
|
|
1371
|
+
meta: {
|
|
1372
|
+
count: actions.count
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
});
|
|
1377
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1378
|
+
where: {
|
|
1379
|
+
releasedAt: null
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1383
|
+
},
|
|
1275
1384
|
async findOne(ctx) {
|
|
1276
1385
|
const id = ctx.params.id;
|
|
1277
1386
|
const releaseService = getService("release", { strapi });
|
|
1387
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1278
1388
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1279
1389
|
if (!release2) {
|
|
1280
1390
|
throw new errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1281
1391
|
}
|
|
1282
|
-
const count = await
|
|
1392
|
+
const count = await releaseActionService.countActions({
|
|
1283
1393
|
filters: {
|
|
1284
1394
|
release: id
|
|
1285
1395
|
}
|
|
1286
1396
|
});
|
|
1287
1397
|
const sanitizedRelease = {
|
|
1288
1398
|
...release2,
|
|
1289
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1399
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1290
1400
|
};
|
|
1291
1401
|
const data = {
|
|
1292
1402
|
...sanitizedRelease,
|
|
@@ -1298,19 +1408,63 @@ const releaseController = {
|
|
|
1298
1408
|
};
|
|
1299
1409
|
ctx.body = { data };
|
|
1300
1410
|
},
|
|
1411
|
+
async mapEntriesToReleases(ctx) {
|
|
1412
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1413
|
+
if (!contentTypeUid || !documentIds) {
|
|
1414
|
+
throw new errors.ValidationError("Missing required query parameters");
|
|
1415
|
+
}
|
|
1416
|
+
const releaseService = getService("release", { strapi });
|
|
1417
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1418
|
+
where: {
|
|
1419
|
+
releasedAt: null,
|
|
1420
|
+
actions: {
|
|
1421
|
+
contentType: contentTypeUid,
|
|
1422
|
+
entryDocumentId: {
|
|
1423
|
+
$in: documentIds
|
|
1424
|
+
},
|
|
1425
|
+
locale
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1428
|
+
populate: {
|
|
1429
|
+
actions: true
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1433
|
+
(acc, release2) => {
|
|
1434
|
+
release2.actions.forEach((action) => {
|
|
1435
|
+
if (action.contentType !== contentTypeUid) {
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
if (locale && action.locale !== locale) {
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
if (!acc[action.entryDocumentId]) {
|
|
1442
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1443
|
+
} else {
|
|
1444
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
return acc;
|
|
1448
|
+
},
|
|
1449
|
+
{}
|
|
1450
|
+
);
|
|
1451
|
+
ctx.body = {
|
|
1452
|
+
data: mappedEntriesInReleases
|
|
1453
|
+
};
|
|
1454
|
+
},
|
|
1301
1455
|
async create(ctx) {
|
|
1302
1456
|
const user = ctx.state.user;
|
|
1303
1457
|
const releaseArgs = ctx.request.body;
|
|
1304
1458
|
await validateRelease(releaseArgs);
|
|
1305
1459
|
const releaseService = getService("release", { strapi });
|
|
1306
1460
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1307
|
-
const permissionsManager = strapi.admin
|
|
1461
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1308
1462
|
ability: ctx.state.userAbility,
|
|
1309
1463
|
model: RELEASE_MODEL_UID
|
|
1310
1464
|
});
|
|
1311
|
-
ctx.
|
|
1465
|
+
ctx.created({
|
|
1312
1466
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1313
|
-
};
|
|
1467
|
+
});
|
|
1314
1468
|
},
|
|
1315
1469
|
async update(ctx) {
|
|
1316
1470
|
const user = ctx.state.user;
|
|
@@ -1319,7 +1473,7 @@ const releaseController = {
|
|
|
1319
1473
|
await validateRelease(releaseArgs);
|
|
1320
1474
|
const releaseService = getService("release", { strapi });
|
|
1321
1475
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1322
|
-
const permissionsManager = strapi.admin
|
|
1476
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1323
1477
|
ability: ctx.state.userAbility,
|
|
1324
1478
|
model: RELEASE_MODEL_UID
|
|
1325
1479
|
});
|
|
@@ -1336,18 +1490,18 @@ const releaseController = {
|
|
|
1336
1490
|
};
|
|
1337
1491
|
},
|
|
1338
1492
|
async publish(ctx) {
|
|
1339
|
-
const user = ctx.state.user;
|
|
1340
1493
|
const id = ctx.params.id;
|
|
1341
1494
|
const releaseService = getService("release", { strapi });
|
|
1342
|
-
const
|
|
1495
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1496
|
+
const release2 = await releaseService.publish(id);
|
|
1343
1497
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1344
|
-
|
|
1498
|
+
releaseActionService.countActions({
|
|
1345
1499
|
filters: {
|
|
1346
1500
|
release: id,
|
|
1347
1501
|
type: "publish"
|
|
1348
1502
|
}
|
|
1349
1503
|
}),
|
|
1350
|
-
|
|
1504
|
+
releaseActionService.countActions({
|
|
1351
1505
|
filters: {
|
|
1352
1506
|
release: id,
|
|
1353
1507
|
type: "unpublish"
|
|
@@ -1365,27 +1519,30 @@ const releaseController = {
|
|
|
1365
1519
|
}
|
|
1366
1520
|
};
|
|
1367
1521
|
const RELEASE_ACTION_SCHEMA = yup$1.object().shape({
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
}).required(),
|
|
1522
|
+
contentType: yup$1.string().required(),
|
|
1523
|
+
entryDocumentId: yup$1.strapiID(),
|
|
1524
|
+
locale: yup$1.string(),
|
|
1372
1525
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1373
1526
|
});
|
|
1374
1527
|
const RELEASE_ACTION_UPDATE_SCHEMA = yup$1.object().shape({
|
|
1375
1528
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1376
1529
|
});
|
|
1530
|
+
const FIND_MANY_ACTIONS_PARAMS = yup$1.object().shape({
|
|
1531
|
+
groupBy: yup$1.string().oneOf(["action", "contentType", "locale"])
|
|
1532
|
+
});
|
|
1377
1533
|
const validateReleaseAction = validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1378
1534
|
const validateReleaseActionUpdateSchema = validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1535
|
+
const validateFindManyActionsParams = validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1379
1536
|
const releaseActionController = {
|
|
1380
1537
|
async create(ctx) {
|
|
1381
1538
|
const releaseId = ctx.params.releaseId;
|
|
1382
1539
|
const releaseActionArgs = ctx.request.body;
|
|
1383
1540
|
await validateReleaseAction(releaseActionArgs);
|
|
1384
|
-
const
|
|
1385
|
-
const releaseAction2 = await
|
|
1386
|
-
ctx.
|
|
1541
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1542
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1543
|
+
ctx.created({
|
|
1387
1544
|
data: releaseAction2
|
|
1388
|
-
};
|
|
1545
|
+
});
|
|
1389
1546
|
},
|
|
1390
1547
|
async createMany(ctx) {
|
|
1391
1548
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1393,12 +1550,15 @@ const releaseActionController = {
|
|
|
1393
1550
|
await Promise.all(
|
|
1394
1551
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1395
1552
|
);
|
|
1553
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1396
1554
|
const releaseService = getService("release", { strapi });
|
|
1397
1555
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1398
1556
|
const releaseActions2 = await Promise.all(
|
|
1399
1557
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1400
1558
|
try {
|
|
1401
|
-
const action = await
|
|
1559
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1560
|
+
disableUpdateReleaseStatus: true
|
|
1561
|
+
});
|
|
1402
1562
|
return action;
|
|
1403
1563
|
} catch (error) {
|
|
1404
1564
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1411,43 +1571,54 @@ const releaseActionController = {
|
|
|
1411
1571
|
return releaseActions2;
|
|
1412
1572
|
});
|
|
1413
1573
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1414
|
-
|
|
1574
|
+
if (newReleaseActions.length > 0) {
|
|
1575
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1576
|
+
}
|
|
1577
|
+
ctx.created({
|
|
1415
1578
|
data: newReleaseActions,
|
|
1416
1579
|
meta: {
|
|
1417
1580
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1418
1581
|
totalEntries: releaseActions.length
|
|
1419
1582
|
}
|
|
1420
|
-
};
|
|
1583
|
+
});
|
|
1421
1584
|
},
|
|
1422
1585
|
async findMany(ctx) {
|
|
1423
1586
|
const releaseId = ctx.params.releaseId;
|
|
1424
|
-
const permissionsManager = strapi.admin
|
|
1587
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1425
1588
|
ability: ctx.state.userAbility,
|
|
1426
1589
|
model: RELEASE_ACTION_MODEL_UID
|
|
1427
1590
|
});
|
|
1591
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1592
|
+
if (ctx.query.groupBy) {
|
|
1593
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1594
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1598
|
+
delete ctx.query.groupBy;
|
|
1428
1599
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1429
|
-
const
|
|
1430
|
-
const { results, pagination } = await
|
|
1431
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1600
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1601
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1432
1602
|
...query
|
|
1433
1603
|
});
|
|
1434
1604
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1435
1605
|
if (acc[action.contentType]) {
|
|
1436
1606
|
return acc;
|
|
1437
1607
|
}
|
|
1438
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1608
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1439
1609
|
ability: ctx.state.userAbility,
|
|
1440
1610
|
model: action.contentType
|
|
1441
1611
|
});
|
|
1442
1612
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1443
1613
|
return acc;
|
|
1444
1614
|
}, {});
|
|
1445
|
-
const sanitizedResults = await
|
|
1615
|
+
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1446
1616
|
...action,
|
|
1447
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1617
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1448
1618
|
}));
|
|
1449
|
-
const groupedData = await
|
|
1450
|
-
const contentTypes2 =
|
|
1619
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1620
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1621
|
+
const releaseService = getService("release", { strapi });
|
|
1451
1622
|
const components = await releaseService.getAllComponents();
|
|
1452
1623
|
ctx.body = {
|
|
1453
1624
|
data: groupedData,
|
|
@@ -1463,8 +1634,8 @@ const releaseActionController = {
|
|
|
1463
1634
|
const releaseId = ctx.params.releaseId;
|
|
1464
1635
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1465
1636
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1466
|
-
const
|
|
1467
|
-
const updatedAction = await
|
|
1637
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1638
|
+
const updatedAction = await releaseActionService.update(
|
|
1468
1639
|
actionId,
|
|
1469
1640
|
releaseId,
|
|
1470
1641
|
releaseActionUpdateArgs
|
|
@@ -1476,17 +1647,71 @@ const releaseActionController = {
|
|
|
1476
1647
|
async delete(ctx) {
|
|
1477
1648
|
const actionId = ctx.params.actionId;
|
|
1478
1649
|
const releaseId = ctx.params.releaseId;
|
|
1479
|
-
const
|
|
1480
|
-
const deletedReleaseAction = await
|
|
1650
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1651
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1481
1652
|
ctx.body = {
|
|
1482
1653
|
data: deletedReleaseAction
|
|
1483
1654
|
};
|
|
1484
1655
|
}
|
|
1485
1656
|
};
|
|
1486
|
-
const
|
|
1657
|
+
const SETTINGS_SCHEMA = yup.object().shape({
|
|
1658
|
+
defaultTimezone: yup.string().nullable().default(null)
|
|
1659
|
+
}).required().noUnknown();
|
|
1660
|
+
const validateSettings = validateYupSchema(SETTINGS_SCHEMA);
|
|
1661
|
+
const settingsController = {
|
|
1662
|
+
async find(ctx) {
|
|
1663
|
+
const settingsService = getService("settings", { strapi });
|
|
1664
|
+
const settings2 = await settingsService.find();
|
|
1665
|
+
ctx.body = { data: settings2 };
|
|
1666
|
+
},
|
|
1667
|
+
async update(ctx) {
|
|
1668
|
+
const settingsBody = ctx.request.body;
|
|
1669
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1670
|
+
const settingsService = getService("settings", { strapi });
|
|
1671
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1672
|
+
ctx.body = { data: updatedSettings };
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
const controllers = {
|
|
1676
|
+
release: releaseController,
|
|
1677
|
+
"release-action": releaseActionController,
|
|
1678
|
+
settings: settingsController
|
|
1679
|
+
};
|
|
1487
1680
|
const release = {
|
|
1488
1681
|
type: "admin",
|
|
1489
1682
|
routes: [
|
|
1683
|
+
{
|
|
1684
|
+
method: "GET",
|
|
1685
|
+
path: "/mapEntriesToReleases",
|
|
1686
|
+
handler: "release.mapEntriesToReleases",
|
|
1687
|
+
config: {
|
|
1688
|
+
policies: [
|
|
1689
|
+
"admin::isAuthenticatedAdmin",
|
|
1690
|
+
{
|
|
1691
|
+
name: "admin::hasPermissions",
|
|
1692
|
+
config: {
|
|
1693
|
+
actions: ["plugin::content-releases.read"]
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
]
|
|
1697
|
+
}
|
|
1698
|
+
},
|
|
1699
|
+
{
|
|
1700
|
+
method: "GET",
|
|
1701
|
+
path: "/getByDocumentAttached",
|
|
1702
|
+
handler: "release.findByDocumentAttached",
|
|
1703
|
+
config: {
|
|
1704
|
+
policies: [
|
|
1705
|
+
"admin::isAuthenticatedAdmin",
|
|
1706
|
+
{
|
|
1707
|
+
name: "admin::hasPermissions",
|
|
1708
|
+
config: {
|
|
1709
|
+
actions: ["plugin::content-releases.read"]
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
]
|
|
1713
|
+
}
|
|
1714
|
+
},
|
|
1490
1715
|
{
|
|
1491
1716
|
method: "POST",
|
|
1492
1717
|
path: "/",
|
|
@@ -1506,7 +1731,7 @@ const release = {
|
|
|
1506
1731
|
{
|
|
1507
1732
|
method: "GET",
|
|
1508
1733
|
path: "/",
|
|
1509
|
-
handler: "release.
|
|
1734
|
+
handler: "release.findPage",
|
|
1510
1735
|
config: {
|
|
1511
1736
|
policies: [
|
|
1512
1737
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1670,13 +1895,50 @@ const releaseAction = {
|
|
|
1670
1895
|
}
|
|
1671
1896
|
]
|
|
1672
1897
|
};
|
|
1898
|
+
const settings = {
|
|
1899
|
+
type: "admin",
|
|
1900
|
+
routes: [
|
|
1901
|
+
{
|
|
1902
|
+
method: "GET",
|
|
1903
|
+
path: "/settings",
|
|
1904
|
+
handler: "settings.find",
|
|
1905
|
+
config: {
|
|
1906
|
+
policies: [
|
|
1907
|
+
"admin::isAuthenticatedAdmin",
|
|
1908
|
+
{
|
|
1909
|
+
name: "admin::hasPermissions",
|
|
1910
|
+
config: {
|
|
1911
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
]
|
|
1915
|
+
}
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
method: "PUT",
|
|
1919
|
+
path: "/settings",
|
|
1920
|
+
handler: "settings.update",
|
|
1921
|
+
config: {
|
|
1922
|
+
policies: [
|
|
1923
|
+
"admin::isAuthenticatedAdmin",
|
|
1924
|
+
{
|
|
1925
|
+
name: "admin::hasPermissions",
|
|
1926
|
+
config: {
|
|
1927
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
]
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
]
|
|
1934
|
+
};
|
|
1673
1935
|
const routes = {
|
|
1936
|
+
settings,
|
|
1674
1937
|
release,
|
|
1675
1938
|
"release-action": releaseAction
|
|
1676
1939
|
};
|
|
1677
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1678
1940
|
const getPlugin = () => {
|
|
1679
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1941
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1680
1942
|
return {
|
|
1681
1943
|
register,
|
|
1682
1944
|
bootstrap,
|