@strapi/content-releases 0.0.0-next.3cc05002fb92029975799c3113971bb5b5198d7c → 0.0.0-next.3fdd03038d558a8190aa7e17574020c5f65395e6
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 +886 -617
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +887 -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,42 @@ 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
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
105
|
+
if (status === "published" && !entry) {
|
|
106
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
107
|
+
}
|
|
108
|
+
return entry;
|
|
109
|
+
}
|
|
110
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
111
|
+
};
|
|
112
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
113
|
+
if (entry.publishedAt) {
|
|
114
|
+
return "published";
|
|
115
|
+
}
|
|
116
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
117
|
+
documentId: entry.documentId,
|
|
118
|
+
locale: entry.locale,
|
|
119
|
+
status: "published",
|
|
120
|
+
fields: ["updatedAt"]
|
|
121
|
+
});
|
|
122
|
+
if (!publishedEntry) {
|
|
123
|
+
return "draft";
|
|
124
|
+
}
|
|
125
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
126
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
127
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
128
|
+
return "modified";
|
|
129
|
+
}
|
|
130
|
+
return "published";
|
|
131
|
+
};
|
|
80
132
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
81
133
|
oldContentTypes,
|
|
82
134
|
contentTypes: contentTypes2
|
|
@@ -98,7 +150,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
98
150
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
99
151
|
const deletedContentTypes = difference(keys(oldContentTypes), keys(contentTypes2)) ?? [];
|
|
100
152
|
if (deletedContentTypes.length) {
|
|
101
|
-
await
|
|
153
|
+
await async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
102
154
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
103
155
|
});
|
|
104
156
|
}
|
|
@@ -117,25 +169,27 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
117
169
|
}
|
|
118
170
|
}
|
|
119
171
|
});
|
|
120
|
-
|
|
172
|
+
async.map(releasesWithoutStatus, async (release2) => {
|
|
121
173
|
const actions = release2.actions;
|
|
122
174
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
123
175
|
for (const action of notValidatedActions) {
|
|
124
176
|
if (action.entry) {
|
|
125
|
-
const
|
|
126
|
-
|
|
177
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
178
|
+
{
|
|
179
|
+
contentType: action.contentType,
|
|
180
|
+
documentId: action.entryDocumentId,
|
|
181
|
+
locale: action.locale
|
|
182
|
+
},
|
|
183
|
+
{ strapi }
|
|
184
|
+
);
|
|
185
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
186
|
+
where: {
|
|
187
|
+
id: action.id
|
|
188
|
+
},
|
|
189
|
+
data: {
|
|
190
|
+
isEntryValid: isEntryValid2
|
|
191
|
+
}
|
|
127
192
|
});
|
|
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
193
|
}
|
|
140
194
|
}
|
|
141
195
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -148,7 +202,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
148
202
|
}
|
|
149
203
|
}
|
|
150
204
|
});
|
|
151
|
-
|
|
205
|
+
async.map(publishedReleases, async (release2) => {
|
|
152
206
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
153
207
|
where: {
|
|
154
208
|
id: release2.id
|
|
@@ -165,7 +219,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
165
219
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
166
220
|
);
|
|
167
221
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
168
|
-
|
|
222
|
+
async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
169
223
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
170
224
|
const contentType = contentTypes2[contentTypeUID];
|
|
171
225
|
if (!isEqual(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -178,30 +232,30 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
178
232
|
release: true
|
|
179
233
|
}
|
|
180
234
|
});
|
|
181
|
-
await
|
|
182
|
-
if (action.entry && action.release) {
|
|
183
|
-
const
|
|
184
|
-
|
|
235
|
+
await async.map(actions, async (action) => {
|
|
236
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
237
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
238
|
+
{
|
|
239
|
+
contentType: contentTypeUID,
|
|
240
|
+
documentId: action.entryDocumentId,
|
|
241
|
+
locale: action.locale
|
|
242
|
+
},
|
|
243
|
+
{ strapi }
|
|
244
|
+
);
|
|
245
|
+
releasesAffected.add(action.release.id);
|
|
246
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
247
|
+
where: {
|
|
248
|
+
id: action.id
|
|
249
|
+
},
|
|
250
|
+
data: {
|
|
251
|
+
isEntryValid: isEntryValid2
|
|
252
|
+
}
|
|
185
253
|
});
|
|
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
254
|
}
|
|
201
255
|
});
|
|
202
256
|
}
|
|
203
257
|
}).then(() => {
|
|
204
|
-
|
|
258
|
+
async.map(releasesAffected, async (releaseId) => {
|
|
205
259
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
206
260
|
});
|
|
207
261
|
});
|
|
@@ -211,13 +265,16 @@ async function disableContentTypeLocalized({ oldContentTypes, contentTypes: cont
|
|
|
211
265
|
if (!oldContentTypes) {
|
|
212
266
|
return;
|
|
213
267
|
}
|
|
268
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
269
|
+
if (!i18nPlugin) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
214
272
|
for (const uid in contentTypes2) {
|
|
215
273
|
if (!oldContentTypes[uid]) {
|
|
216
274
|
continue;
|
|
217
275
|
}
|
|
218
276
|
const oldContentType = oldContentTypes[uid];
|
|
219
277
|
const contentType = contentTypes2[uid];
|
|
220
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
221
278
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
222
279
|
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
223
280
|
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -230,13 +287,16 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
230
287
|
if (!oldContentTypes) {
|
|
231
288
|
return;
|
|
232
289
|
}
|
|
290
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
291
|
+
if (!i18nPlugin) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
233
294
|
for (const uid in contentTypes2) {
|
|
234
295
|
if (!oldContentTypes[uid]) {
|
|
235
296
|
continue;
|
|
236
297
|
}
|
|
237
298
|
const oldContentType = oldContentTypes[uid];
|
|
238
299
|
const contentType = contentTypes2[uid];
|
|
239
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
240
300
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
241
301
|
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
242
302
|
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
@@ -247,11 +307,43 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
247
307
|
}
|
|
248
308
|
}
|
|
249
309
|
}
|
|
250
|
-
const
|
|
310
|
+
const addEntryDocumentToReleaseActions = {
|
|
311
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
312
|
+
async up(trx, db) {
|
|
313
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
314
|
+
if (!hasTable) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
318
|
+
if (hasPolymorphicColumn) {
|
|
319
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
320
|
+
"strapi_release_actions",
|
|
321
|
+
"entry_document_id"
|
|
322
|
+
);
|
|
323
|
+
if (!hasEntryDocumentIdColumn) {
|
|
324
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
325
|
+
table.string("entry_document_id");
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
329
|
+
async.map(releaseActions, async (action) => {
|
|
330
|
+
const { target_type, target_id } = action;
|
|
331
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
332
|
+
if (entry) {
|
|
333
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
async down() {
|
|
339
|
+
throw new Error("not implemented");
|
|
340
|
+
}
|
|
341
|
+
};
|
|
251
342
|
const register = async ({ strapi: strapi2 }) => {
|
|
252
|
-
if (features
|
|
253
|
-
await strapi2.admin
|
|
254
|
-
strapi2.
|
|
343
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
344
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
345
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
346
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
255
347
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
256
348
|
}
|
|
257
349
|
if (strapi2.plugin("graphql")) {
|
|
@@ -260,129 +352,134 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
260
352
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
261
353
|
}
|
|
262
354
|
};
|
|
263
|
-
const
|
|
355
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
356
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
357
|
+
where: {
|
|
358
|
+
actions: {
|
|
359
|
+
contentType,
|
|
360
|
+
entryDocumentId: entry.documentId,
|
|
361
|
+
locale: entry.locale
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
366
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
367
|
+
where: {
|
|
368
|
+
contentType,
|
|
369
|
+
entryDocumentId: entry.documentId,
|
|
370
|
+
locale: entry.locale
|
|
371
|
+
},
|
|
372
|
+
data: {
|
|
373
|
+
isEntryValid: entryStatus
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
for (const release2 of releases) {
|
|
377
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
381
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
382
|
+
where: {
|
|
383
|
+
actions: params
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
387
|
+
where: params
|
|
388
|
+
});
|
|
389
|
+
for (const release2 of releases) {
|
|
390
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
394
|
+
if (ctx.action !== "delete") {
|
|
395
|
+
return next();
|
|
396
|
+
}
|
|
397
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
398
|
+
return next();
|
|
399
|
+
}
|
|
400
|
+
const contentType = ctx.contentType.uid;
|
|
401
|
+
const { documentId, locale } = ctx.params;
|
|
402
|
+
const result = await next();
|
|
403
|
+
if (!result) {
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
408
|
+
contentType,
|
|
409
|
+
entryDocumentId: documentId,
|
|
410
|
+
...locale !== "*" && { locale }
|
|
411
|
+
});
|
|
412
|
+
} catch (error) {
|
|
413
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
414
|
+
error
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
return result;
|
|
418
|
+
};
|
|
419
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
420
|
+
if (ctx.action !== "update") {
|
|
421
|
+
return next();
|
|
422
|
+
}
|
|
423
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
424
|
+
return next();
|
|
425
|
+
}
|
|
426
|
+
const contentType = ctx.contentType.uid;
|
|
427
|
+
const result = await next();
|
|
428
|
+
if (!result) {
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
435
|
+
error
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
return result;
|
|
439
|
+
};
|
|
440
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
441
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
442
|
+
where: {
|
|
443
|
+
actions: params
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
447
|
+
where: params
|
|
448
|
+
});
|
|
449
|
+
for (const release2 of releases) {
|
|
450
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
451
|
+
}
|
|
452
|
+
};
|
|
264
453
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
265
|
-
if (features
|
|
454
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
266
455
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
267
456
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
268
457
|
);
|
|
269
458
|
strapi2.db.lifecycles.subscribe({
|
|
270
459
|
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
460
|
/**
|
|
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
|
|
461
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
313
462
|
*/
|
|
314
463
|
async afterDeleteMany(event) {
|
|
315
464
|
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
|
-
}
|
|
465
|
+
const model = strapi2.getModel(event.model.uid);
|
|
466
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
467
|
+
const { where } = event.params;
|
|
468
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
469
|
+
contentType: model.uid,
|
|
470
|
+
locale: where?.locale ?? null,
|
|
471
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
338
472
|
});
|
|
339
|
-
for (const release2 of releases) {
|
|
340
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
341
|
-
}
|
|
342
473
|
}
|
|
343
474
|
} catch (error) {
|
|
344
475
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
345
476
|
error
|
|
346
477
|
});
|
|
347
478
|
}
|
|
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
479
|
}
|
|
385
480
|
});
|
|
481
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
482
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
386
483
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
387
484
|
strapi2.log.error(
|
|
388
485
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -390,7 +487,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
390
487
|
throw err;
|
|
391
488
|
});
|
|
392
489
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
393
|
-
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
490
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
394
491
|
});
|
|
395
492
|
}
|
|
396
493
|
};
|
|
@@ -474,15 +571,13 @@ const schema = {
|
|
|
474
571
|
enum: ["publish", "unpublish"],
|
|
475
572
|
required: true
|
|
476
573
|
},
|
|
477
|
-
entry: {
|
|
478
|
-
type: "relation",
|
|
479
|
-
relation: "morphToOne",
|
|
480
|
-
configurable: false
|
|
481
|
-
},
|
|
482
574
|
contentType: {
|
|
483
575
|
type: "string",
|
|
484
576
|
required: true
|
|
485
577
|
},
|
|
578
|
+
entryDocumentId: {
|
|
579
|
+
type: "string"
|
|
580
|
+
},
|
|
486
581
|
locale: {
|
|
487
582
|
type: "string"
|
|
488
583
|
},
|
|
@@ -504,18 +599,6 @@ const contentTypes = {
|
|
|
504
599
|
release: release$1,
|
|
505
600
|
"release-action": releaseAction$1
|
|
506
601
|
};
|
|
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
602
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
520
603
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
521
604
|
strapi2.eventHub.emit(event, {
|
|
@@ -524,93 +607,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
524
607
|
release: release2
|
|
525
608
|
});
|
|
526
609
|
};
|
|
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
610
|
const getFormattedActions = async (releaseId) => {
|
|
574
611
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
575
612
|
where: {
|
|
576
613
|
release: {
|
|
577
614
|
id: releaseId
|
|
578
615
|
}
|
|
579
|
-
},
|
|
580
|
-
populate: {
|
|
581
|
-
entry: {
|
|
582
|
-
fields: ["id"]
|
|
583
|
-
}
|
|
584
616
|
}
|
|
585
617
|
});
|
|
586
618
|
if (actions.length === 0) {
|
|
587
619
|
throw new errors.ValidationError("No entries to publish");
|
|
588
620
|
}
|
|
589
|
-
const
|
|
590
|
-
const singleTypeActions = [];
|
|
621
|
+
const formattedActions = {};
|
|
591
622
|
for (const action of actions) {
|
|
592
623
|
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
|
-
});
|
|
624
|
+
if (!formattedActions[contentTypeUid]) {
|
|
625
|
+
formattedActions[contentTypeUid] = {
|
|
626
|
+
publish: [],
|
|
627
|
+
unpublish: []
|
|
628
|
+
};
|
|
611
629
|
}
|
|
630
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
631
|
+
documentId: action.entryDocumentId,
|
|
632
|
+
locale: action.locale
|
|
633
|
+
});
|
|
612
634
|
}
|
|
613
|
-
return
|
|
635
|
+
return formattedActions;
|
|
614
636
|
};
|
|
615
637
|
return {
|
|
616
638
|
async create(releaseData, { user }) {
|
|
@@ -625,7 +647,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
625
647
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
626
648
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
627
649
|
]);
|
|
628
|
-
const release2 = await strapi2.
|
|
650
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
629
651
|
data: {
|
|
630
652
|
...releaseWithCreatorFields,
|
|
631
653
|
status: "empty"
|
|
@@ -639,94 +661,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
639
661
|
return release2;
|
|
640
662
|
},
|
|
641
663
|
async findOne(id, query = {}) {
|
|
642
|
-
const
|
|
643
|
-
|
|
664
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
665
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
666
|
+
...dbQuery,
|
|
667
|
+
where: { id }
|
|
644
668
|
});
|
|
645
669
|
return release2;
|
|
646
670
|
},
|
|
647
671
|
findPage(query) {
|
|
648
|
-
|
|
649
|
-
|
|
672
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
673
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
674
|
+
...dbQuery,
|
|
650
675
|
populate: {
|
|
651
676
|
actions: {
|
|
652
|
-
// @ts-expect-error Ignore missing properties
|
|
653
677
|
count: true
|
|
654
678
|
}
|
|
655
679
|
}
|
|
656
680
|
});
|
|
657
681
|
},
|
|
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;
|
|
682
|
+
findMany(query) {
|
|
683
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
684
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
685
|
+
...dbQuery
|
|
730
686
|
});
|
|
731
687
|
},
|
|
732
688
|
async update(id, releaseData, { user }) {
|
|
@@ -741,19 +697,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
741
697
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
742
698
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
743
699
|
]);
|
|
744
|
-
const release2 = await strapi2.
|
|
700
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
745
701
|
if (!release2) {
|
|
746
702
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
747
703
|
}
|
|
748
704
|
if (release2.releasedAt) {
|
|
749
705
|
throw new errors.ValidationError("Release already published");
|
|
750
706
|
}
|
|
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
|
|
707
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
708
|
+
where: { id },
|
|
757
709
|
data: releaseWithCreatorFields
|
|
758
710
|
});
|
|
759
711
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -766,130 +718,6 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
766
718
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
767
719
|
return updatedRelease;
|
|
768
720
|
},
|
|
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
721
|
async getAllComponents() {
|
|
894
722
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
895
723
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -903,10 +731,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
903
731
|
return componentsMap;
|
|
904
732
|
},
|
|
905
733
|
async delete(releaseId) {
|
|
906
|
-
const release2 = await strapi2.
|
|
734
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
735
|
+
where: { id: releaseId },
|
|
907
736
|
populate: {
|
|
908
737
|
actions: {
|
|
909
|
-
|
|
738
|
+
select: ["id"]
|
|
910
739
|
}
|
|
911
740
|
}
|
|
912
741
|
});
|
|
@@ -924,7 +753,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
924
753
|
}
|
|
925
754
|
}
|
|
926
755
|
});
|
|
927
|
-
await strapi2.
|
|
756
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
757
|
+
where: {
|
|
758
|
+
id: releaseId
|
|
759
|
+
}
|
|
760
|
+
});
|
|
928
761
|
});
|
|
929
762
|
if (release2.scheduledAt) {
|
|
930
763
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -950,22 +783,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
950
783
|
}
|
|
951
784
|
try {
|
|
952
785
|
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
953
|
-
const
|
|
954
|
-
|
|
786
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
787
|
+
await strapi2.db.transaction(
|
|
788
|
+
async () => Promise.all(
|
|
789
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
790
|
+
const contentType = contentTypeUid;
|
|
791
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
792
|
+
return Promise.all([
|
|
793
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
794
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
795
|
+
]);
|
|
796
|
+
})
|
|
797
|
+
)
|
|
955
798
|
);
|
|
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
799
|
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
970
800
|
where: {
|
|
971
801
|
id: releaseId
|
|
@@ -995,13 +825,226 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
995
825
|
};
|
|
996
826
|
}
|
|
997
827
|
});
|
|
998
|
-
if (error) {
|
|
999
|
-
throw error;
|
|
1000
|
-
}
|
|
1001
|
-
return release2;
|
|
828
|
+
if (error instanceof Error) {
|
|
829
|
+
throw error;
|
|
830
|
+
}
|
|
831
|
+
return release2;
|
|
832
|
+
},
|
|
833
|
+
async updateReleaseStatus(releaseId) {
|
|
834
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
835
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
836
|
+
releaseActionService.countActions({
|
|
837
|
+
filters: {
|
|
838
|
+
release: releaseId
|
|
839
|
+
}
|
|
840
|
+
}),
|
|
841
|
+
releaseActionService.countActions({
|
|
842
|
+
filters: {
|
|
843
|
+
release: releaseId,
|
|
844
|
+
isEntryValid: false
|
|
845
|
+
}
|
|
846
|
+
})
|
|
847
|
+
]);
|
|
848
|
+
if (totalActions > 0) {
|
|
849
|
+
if (invalidActions > 0) {
|
|
850
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
851
|
+
where: {
|
|
852
|
+
id: releaseId
|
|
853
|
+
},
|
|
854
|
+
data: {
|
|
855
|
+
status: "blocked"
|
|
856
|
+
}
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
860
|
+
where: {
|
|
861
|
+
id: releaseId
|
|
862
|
+
},
|
|
863
|
+
data: {
|
|
864
|
+
status: "ready"
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
869
|
+
where: {
|
|
870
|
+
id: releaseId
|
|
871
|
+
},
|
|
872
|
+
data: {
|
|
873
|
+
status: "empty"
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
};
|
|
879
|
+
const getGroupName = (queryValue) => {
|
|
880
|
+
switch (queryValue) {
|
|
881
|
+
case "contentType":
|
|
882
|
+
return "contentType.displayName";
|
|
883
|
+
case "type":
|
|
884
|
+
return "type";
|
|
885
|
+
case "locale":
|
|
886
|
+
return _.getOr("No locale", "locale.name");
|
|
887
|
+
default:
|
|
888
|
+
return "contentType.displayName";
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
892
|
+
const getLocalesDataForActions = async () => {
|
|
893
|
+
if (!strapi2.plugin("i18n")) {
|
|
894
|
+
return {};
|
|
895
|
+
}
|
|
896
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
897
|
+
return allLocales.reduce((acc, locale) => {
|
|
898
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
899
|
+
return acc;
|
|
900
|
+
}, {});
|
|
901
|
+
};
|
|
902
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
903
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
904
|
+
const contentTypesData = {};
|
|
905
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
906
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
907
|
+
uid: contentTypeUid
|
|
908
|
+
});
|
|
909
|
+
contentTypesData[contentTypeUid] = {
|
|
910
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
911
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
return contentTypesData;
|
|
915
|
+
};
|
|
916
|
+
return {
|
|
917
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
918
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
919
|
+
strapi: strapi2
|
|
920
|
+
});
|
|
921
|
+
await Promise.all([
|
|
922
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
923
|
+
validateUniqueEntry(releaseId, action)
|
|
924
|
+
]);
|
|
925
|
+
const model = strapi2.contentType(action.contentType);
|
|
926
|
+
if (model.kind === "singleType") {
|
|
927
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
928
|
+
if (!document) {
|
|
929
|
+
throw new errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
930
|
+
}
|
|
931
|
+
action.entryDocumentId = document.documentId;
|
|
932
|
+
}
|
|
933
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
934
|
+
if (!release2) {
|
|
935
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
936
|
+
}
|
|
937
|
+
if (release2.releasedAt) {
|
|
938
|
+
throw new errors.ValidationError("Release already published");
|
|
939
|
+
}
|
|
940
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
941
|
+
{
|
|
942
|
+
contentType: action.contentType,
|
|
943
|
+
documentId: action.entryDocumentId,
|
|
944
|
+
locale: action.locale
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
strapi: strapi2
|
|
948
|
+
}
|
|
949
|
+
) : true;
|
|
950
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
951
|
+
data: {
|
|
952
|
+
...action,
|
|
953
|
+
release: release2.id,
|
|
954
|
+
isEntryValid: actionStatus
|
|
955
|
+
},
|
|
956
|
+
populate: { release: { select: ["id"] } }
|
|
957
|
+
});
|
|
958
|
+
if (!disableUpdateReleaseStatus) {
|
|
959
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
960
|
+
}
|
|
961
|
+
return releaseAction2;
|
|
962
|
+
},
|
|
963
|
+
async findPage(releaseId, query) {
|
|
964
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
965
|
+
where: { id: releaseId },
|
|
966
|
+
select: ["id"]
|
|
967
|
+
});
|
|
968
|
+
if (!release2) {
|
|
969
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
970
|
+
}
|
|
971
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
972
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
973
|
+
...dbQuery,
|
|
974
|
+
where: {
|
|
975
|
+
release: releaseId
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
979
|
+
const actionsWithEntry = await async.map(actions, async (action) => {
|
|
980
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
981
|
+
const entry = await getEntry(
|
|
982
|
+
{
|
|
983
|
+
contentType: action.contentType,
|
|
984
|
+
documentId: action.entryDocumentId,
|
|
985
|
+
locale: action.locale,
|
|
986
|
+
populate,
|
|
987
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
988
|
+
},
|
|
989
|
+
{ strapi: strapi2 }
|
|
990
|
+
);
|
|
991
|
+
return {
|
|
992
|
+
...action,
|
|
993
|
+
entry,
|
|
994
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
995
|
+
};
|
|
996
|
+
});
|
|
997
|
+
return {
|
|
998
|
+
results: actionsWithEntry,
|
|
999
|
+
pagination
|
|
1000
|
+
};
|
|
1001
|
+
},
|
|
1002
|
+
async groupActions(actions, groupBy) {
|
|
1003
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1004
|
+
if (!acc.includes(action.contentType)) {
|
|
1005
|
+
acc.push(action.contentType);
|
|
1006
|
+
}
|
|
1007
|
+
return acc;
|
|
1008
|
+
}, []);
|
|
1009
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1010
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1011
|
+
const formattedData = actions.map((action) => {
|
|
1012
|
+
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1013
|
+
return {
|
|
1014
|
+
...action,
|
|
1015
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1016
|
+
contentType: {
|
|
1017
|
+
displayName,
|
|
1018
|
+
mainFieldValue: action.entry[mainField],
|
|
1019
|
+
uid: action.contentType
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
});
|
|
1023
|
+
const groupName = getGroupName(groupBy);
|
|
1024
|
+
return _.groupBy(groupName)(formattedData);
|
|
1002
1025
|
},
|
|
1003
|
-
|
|
1004
|
-
const
|
|
1026
|
+
getContentTypeModelsFromActions(actions) {
|
|
1027
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1028
|
+
if (!acc.includes(action.contentType)) {
|
|
1029
|
+
acc.push(action.contentType);
|
|
1030
|
+
}
|
|
1031
|
+
return acc;
|
|
1032
|
+
}, []);
|
|
1033
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1034
|
+
(acc, contentTypeUid) => {
|
|
1035
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1036
|
+
return acc;
|
|
1037
|
+
},
|
|
1038
|
+
{}
|
|
1039
|
+
);
|
|
1040
|
+
return contentTypeModelsMap;
|
|
1041
|
+
},
|
|
1042
|
+
async countActions(query) {
|
|
1043
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1044
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1045
|
+
},
|
|
1046
|
+
async update(actionId, releaseId, update) {
|
|
1047
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1005
1048
|
where: {
|
|
1006
1049
|
id: actionId,
|
|
1007
1050
|
release: {
|
|
@@ -1010,17 +1053,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1010
1053
|
$null: true
|
|
1011
1054
|
}
|
|
1012
1055
|
}
|
|
1013
|
-
}
|
|
1014
|
-
data: update
|
|
1056
|
+
}
|
|
1015
1057
|
});
|
|
1016
|
-
if (!
|
|
1058
|
+
if (!action) {
|
|
1017
1059
|
throw new errors.NotFoundError(
|
|
1018
1060
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1019
1061
|
);
|
|
1020
1062
|
}
|
|
1063
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1064
|
+
{
|
|
1065
|
+
contentType: action.contentType,
|
|
1066
|
+
documentId: action.entryDocumentId,
|
|
1067
|
+
locale: action.locale
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
strapi: strapi2
|
|
1071
|
+
}
|
|
1072
|
+
) : true;
|
|
1073
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1074
|
+
where: {
|
|
1075
|
+
id: actionId,
|
|
1076
|
+
release: {
|
|
1077
|
+
id: releaseId,
|
|
1078
|
+
releasedAt: {
|
|
1079
|
+
$null: true
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
data: {
|
|
1084
|
+
...update,
|
|
1085
|
+
isEntryValid: actionStatus
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1021
1089
|
return updatedAction;
|
|
1022
1090
|
},
|
|
1023
|
-
async
|
|
1091
|
+
async delete(actionId, releaseId) {
|
|
1024
1092
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1025
1093
|
where: {
|
|
1026
1094
|
id: actionId,
|
|
@@ -1037,51 +1105,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1037
1105
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1038
1106
|
);
|
|
1039
1107
|
}
|
|
1040
|
-
|
|
1108
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1041
1109
|
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
1110
|
}
|
|
1086
1111
|
};
|
|
1087
1112
|
};
|
|
@@ -1093,37 +1118,43 @@ class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
|
1093
1118
|
}
|
|
1094
1119
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1095
1120
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1096
|
-
const release2 = await strapi2.
|
|
1097
|
-
|
|
1121
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1122
|
+
where: {
|
|
1123
|
+
id: releaseId
|
|
1124
|
+
},
|
|
1125
|
+
populate: {
|
|
1126
|
+
actions: true
|
|
1127
|
+
}
|
|
1098
1128
|
});
|
|
1099
1129
|
if (!release2) {
|
|
1100
1130
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1101
1131
|
}
|
|
1102
1132
|
const isEntryInRelease = release2.actions.some(
|
|
1103
|
-
(action) =>
|
|
1133
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1104
1134
|
);
|
|
1105
1135
|
if (isEntryInRelease) {
|
|
1106
1136
|
throw new AlreadyOnReleaseError(
|
|
1107
|
-
`Entry with
|
|
1137
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1108
1138
|
);
|
|
1109
1139
|
}
|
|
1110
1140
|
},
|
|
1111
|
-
|
|
1141
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1112
1142
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1113
1143
|
if (!contentType) {
|
|
1114
1144
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1115
1145
|
}
|
|
1116
|
-
if (!contentType
|
|
1146
|
+
if (!contentTypes$1.hasDraftAndPublish(contentType)) {
|
|
1117
1147
|
throw new errors.ValidationError(
|
|
1118
1148
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1119
1149
|
);
|
|
1120
1150
|
}
|
|
1151
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1152
|
+
throw new errors.ValidationError("Document id is required for collection type");
|
|
1153
|
+
}
|
|
1121
1154
|
},
|
|
1122
1155
|
async validatePendingReleasesLimit() {
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1126
|
-
);
|
|
1156
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1157
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1127
1158
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1128
1159
|
filters: {
|
|
1129
1160
|
releasedAt: {
|
|
@@ -1136,8 +1167,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1136
1167
|
}
|
|
1137
1168
|
},
|
|
1138
1169
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1139
|
-
const pendingReleases = await strapi2.
|
|
1140
|
-
|
|
1170
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1171
|
+
where: {
|
|
1141
1172
|
releasedAt: {
|
|
1142
1173
|
$null: true
|
|
1143
1174
|
},
|
|
@@ -1166,7 +1197,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1166
1197
|
}
|
|
1167
1198
|
const job = scheduleJob(scheduleDate, async () => {
|
|
1168
1199
|
try {
|
|
1169
|
-
await getService("release").publish(releaseId);
|
|
1200
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1170
1201
|
} catch (error) {
|
|
1171
1202
|
}
|
|
1172
1203
|
this.cancel(releaseId);
|
|
@@ -1208,85 +1239,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1208
1239
|
}
|
|
1209
1240
|
};
|
|
1210
1241
|
};
|
|
1242
|
+
const DEFAULT_SETTINGS = {
|
|
1243
|
+
defaultTimezone: null
|
|
1244
|
+
};
|
|
1245
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1246
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1247
|
+
return {
|
|
1248
|
+
async update({ settings: settings2 }) {
|
|
1249
|
+
const store = await getStore();
|
|
1250
|
+
store.set({ key: "settings", value: settings2 });
|
|
1251
|
+
return settings2;
|
|
1252
|
+
},
|
|
1253
|
+
async find() {
|
|
1254
|
+
const store = await getStore();
|
|
1255
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1256
|
+
return {
|
|
1257
|
+
...DEFAULT_SETTINGS,
|
|
1258
|
+
...settings2 || {}
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
};
|
|
1211
1263
|
const services = {
|
|
1212
1264
|
release: createReleaseService,
|
|
1265
|
+
"release-action": createReleaseActionService,
|
|
1213
1266
|
"release-validation": createReleaseValidationService,
|
|
1214
|
-
scheduling: createSchedulingService
|
|
1267
|
+
scheduling: createSchedulingService,
|
|
1268
|
+
settings: createSettingsService
|
|
1215
1269
|
};
|
|
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()
|
|
1270
|
+
const RELEASE_SCHEMA = yup$1.object().shape({
|
|
1271
|
+
name: yup$1.string().trim().required(),
|
|
1272
|
+
scheduledAt: yup$1.string().nullable(),
|
|
1273
|
+
timezone: yup$1.string().when("scheduledAt", {
|
|
1274
|
+
is: (value) => value !== null && value !== void 0,
|
|
1275
|
+
then: yup$1.string().required(),
|
|
1276
|
+
otherwise: yup$1.string().nullable()
|
|
1234
1277
|
})
|
|
1235
1278
|
}).required().noUnknown();
|
|
1279
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = yup$1.object().shape({
|
|
1280
|
+
contentType: yup$1.string().required(),
|
|
1281
|
+
entryDocumentId: yup$1.string().nullable(),
|
|
1282
|
+
hasEntryAttached: yup$1.string().nullable(),
|
|
1283
|
+
locale: yup$1.string().nullable()
|
|
1284
|
+
}).required().noUnknown();
|
|
1236
1285
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
1286
|
+
const validatefindByDocumentAttachedParams = validateYupSchema(
|
|
1287
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1288
|
+
);
|
|
1237
1289
|
const releaseController = {
|
|
1238
|
-
|
|
1239
|
-
|
|
1290
|
+
/**
|
|
1291
|
+
* Find releases based on documents attached or not to the release.
|
|
1292
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1293
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1294
|
+
*/
|
|
1295
|
+
async findByDocumentAttached(ctx) {
|
|
1296
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1240
1297
|
ability: ctx.state.userAbility,
|
|
1241
1298
|
model: RELEASE_MODEL_UID
|
|
1242
1299
|
});
|
|
1243
1300
|
await permissionsManager.validateQuery(ctx.query);
|
|
1244
1301
|
const releaseService = getService("release", { strapi });
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1302
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1303
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1304
|
+
const model = strapi.getModel(query.contentType);
|
|
1305
|
+
if (model.kind && model.kind === "singleType") {
|
|
1306
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1307
|
+
if (!document) {
|
|
1308
|
+
throw new errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1309
|
+
}
|
|
1310
|
+
query.entryDocumentId = document.documentId;
|
|
1311
|
+
}
|
|
1312
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1313
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1314
|
+
if (isEntryAttached) {
|
|
1315
|
+
const releases = await releaseService.findMany({
|
|
1316
|
+
where: {
|
|
1317
|
+
releasedAt: null,
|
|
1318
|
+
actions: {
|
|
1319
|
+
contentType,
|
|
1320
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1321
|
+
locale: locale ?? null
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
populate: {
|
|
1260
1325
|
actions: {
|
|
1261
|
-
|
|
1262
|
-
|
|
1326
|
+
fields: ["type"],
|
|
1327
|
+
filters: {
|
|
1328
|
+
contentType,
|
|
1329
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1330
|
+
locale: locale ?? null
|
|
1263
1331
|
}
|
|
1264
1332
|
}
|
|
1265
|
-
}
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
1335
|
+
ctx.body = { data: releases };
|
|
1336
|
+
} else {
|
|
1337
|
+
const relatedReleases = await releaseService.findMany({
|
|
1338
|
+
where: {
|
|
1339
|
+
releasedAt: null,
|
|
1340
|
+
actions: {
|
|
1341
|
+
contentType,
|
|
1342
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1343
|
+
locale: locale ?? null
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1266
1346
|
});
|
|
1267
|
-
const
|
|
1347
|
+
const releases = await releaseService.findMany({
|
|
1268
1348
|
where: {
|
|
1349
|
+
$or: [
|
|
1350
|
+
{
|
|
1351
|
+
id: {
|
|
1352
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1353
|
+
}
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
actions: null
|
|
1357
|
+
}
|
|
1358
|
+
],
|
|
1269
1359
|
releasedAt: null
|
|
1270
1360
|
}
|
|
1271
1361
|
});
|
|
1272
|
-
ctx.body = { data
|
|
1362
|
+
ctx.body = { data: releases };
|
|
1273
1363
|
}
|
|
1274
1364
|
},
|
|
1365
|
+
async findPage(ctx) {
|
|
1366
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1367
|
+
ability: ctx.state.userAbility,
|
|
1368
|
+
model: RELEASE_MODEL_UID
|
|
1369
|
+
});
|
|
1370
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1371
|
+
const releaseService = getService("release", { strapi });
|
|
1372
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1373
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1374
|
+
const data = results.map((release2) => {
|
|
1375
|
+
const { actions, ...releaseData } = release2;
|
|
1376
|
+
return {
|
|
1377
|
+
...releaseData,
|
|
1378
|
+
actions: {
|
|
1379
|
+
meta: {
|
|
1380
|
+
count: actions.count
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
});
|
|
1385
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1386
|
+
where: {
|
|
1387
|
+
releasedAt: null
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1391
|
+
},
|
|
1275
1392
|
async findOne(ctx) {
|
|
1276
1393
|
const id = ctx.params.id;
|
|
1277
1394
|
const releaseService = getService("release", { strapi });
|
|
1395
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1278
1396
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1279
1397
|
if (!release2) {
|
|
1280
1398
|
throw new errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1281
1399
|
}
|
|
1282
|
-
const count = await
|
|
1400
|
+
const count = await releaseActionService.countActions({
|
|
1283
1401
|
filters: {
|
|
1284
1402
|
release: id
|
|
1285
1403
|
}
|
|
1286
1404
|
});
|
|
1287
1405
|
const sanitizedRelease = {
|
|
1288
1406
|
...release2,
|
|
1289
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1407
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1290
1408
|
};
|
|
1291
1409
|
const data = {
|
|
1292
1410
|
...sanitizedRelease,
|
|
@@ -1298,19 +1416,63 @@ const releaseController = {
|
|
|
1298
1416
|
};
|
|
1299
1417
|
ctx.body = { data };
|
|
1300
1418
|
},
|
|
1419
|
+
async mapEntriesToReleases(ctx) {
|
|
1420
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1421
|
+
if (!contentTypeUid || !documentIds) {
|
|
1422
|
+
throw new errors.ValidationError("Missing required query parameters");
|
|
1423
|
+
}
|
|
1424
|
+
const releaseService = getService("release", { strapi });
|
|
1425
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1426
|
+
where: {
|
|
1427
|
+
releasedAt: null,
|
|
1428
|
+
actions: {
|
|
1429
|
+
contentType: contentTypeUid,
|
|
1430
|
+
entryDocumentId: {
|
|
1431
|
+
$in: documentIds
|
|
1432
|
+
},
|
|
1433
|
+
locale
|
|
1434
|
+
}
|
|
1435
|
+
},
|
|
1436
|
+
populate: {
|
|
1437
|
+
actions: true
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1440
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1441
|
+
(acc, release2) => {
|
|
1442
|
+
release2.actions.forEach((action) => {
|
|
1443
|
+
if (action.contentType !== contentTypeUid) {
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
if (locale && action.locale !== locale) {
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
if (!acc[action.entryDocumentId]) {
|
|
1450
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1451
|
+
} else {
|
|
1452
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
return acc;
|
|
1456
|
+
},
|
|
1457
|
+
{}
|
|
1458
|
+
);
|
|
1459
|
+
ctx.body = {
|
|
1460
|
+
data: mappedEntriesInReleases
|
|
1461
|
+
};
|
|
1462
|
+
},
|
|
1301
1463
|
async create(ctx) {
|
|
1302
1464
|
const user = ctx.state.user;
|
|
1303
1465
|
const releaseArgs = ctx.request.body;
|
|
1304
1466
|
await validateRelease(releaseArgs);
|
|
1305
1467
|
const releaseService = getService("release", { strapi });
|
|
1306
1468
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1307
|
-
const permissionsManager = strapi.admin
|
|
1469
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1308
1470
|
ability: ctx.state.userAbility,
|
|
1309
1471
|
model: RELEASE_MODEL_UID
|
|
1310
1472
|
});
|
|
1311
|
-
ctx.
|
|
1473
|
+
ctx.created({
|
|
1312
1474
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1313
|
-
};
|
|
1475
|
+
});
|
|
1314
1476
|
},
|
|
1315
1477
|
async update(ctx) {
|
|
1316
1478
|
const user = ctx.state.user;
|
|
@@ -1319,7 +1481,7 @@ const releaseController = {
|
|
|
1319
1481
|
await validateRelease(releaseArgs);
|
|
1320
1482
|
const releaseService = getService("release", { strapi });
|
|
1321
1483
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1322
|
-
const permissionsManager = strapi.admin
|
|
1484
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1323
1485
|
ability: ctx.state.userAbility,
|
|
1324
1486
|
model: RELEASE_MODEL_UID
|
|
1325
1487
|
});
|
|
@@ -1336,18 +1498,18 @@ const releaseController = {
|
|
|
1336
1498
|
};
|
|
1337
1499
|
},
|
|
1338
1500
|
async publish(ctx) {
|
|
1339
|
-
const user = ctx.state.user;
|
|
1340
1501
|
const id = ctx.params.id;
|
|
1341
1502
|
const releaseService = getService("release", { strapi });
|
|
1342
|
-
const
|
|
1503
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1504
|
+
const release2 = await releaseService.publish(id);
|
|
1343
1505
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1344
|
-
|
|
1506
|
+
releaseActionService.countActions({
|
|
1345
1507
|
filters: {
|
|
1346
1508
|
release: id,
|
|
1347
1509
|
type: "publish"
|
|
1348
1510
|
}
|
|
1349
1511
|
}),
|
|
1350
|
-
|
|
1512
|
+
releaseActionService.countActions({
|
|
1351
1513
|
filters: {
|
|
1352
1514
|
release: id,
|
|
1353
1515
|
type: "unpublish"
|
|
@@ -1365,27 +1527,30 @@ const releaseController = {
|
|
|
1365
1527
|
}
|
|
1366
1528
|
};
|
|
1367
1529
|
const RELEASE_ACTION_SCHEMA = yup$1.object().shape({
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
}).required(),
|
|
1530
|
+
contentType: yup$1.string().required(),
|
|
1531
|
+
entryDocumentId: yup$1.strapiID(),
|
|
1532
|
+
locale: yup$1.string(),
|
|
1372
1533
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1373
1534
|
});
|
|
1374
1535
|
const RELEASE_ACTION_UPDATE_SCHEMA = yup$1.object().shape({
|
|
1375
1536
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1376
1537
|
});
|
|
1538
|
+
const FIND_MANY_ACTIONS_PARAMS = yup$1.object().shape({
|
|
1539
|
+
groupBy: yup$1.string().oneOf(["action", "contentType", "locale"])
|
|
1540
|
+
});
|
|
1377
1541
|
const validateReleaseAction = validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1378
1542
|
const validateReleaseActionUpdateSchema = validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1543
|
+
const validateFindManyActionsParams = validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1379
1544
|
const releaseActionController = {
|
|
1380
1545
|
async create(ctx) {
|
|
1381
1546
|
const releaseId = ctx.params.releaseId;
|
|
1382
1547
|
const releaseActionArgs = ctx.request.body;
|
|
1383
1548
|
await validateReleaseAction(releaseActionArgs);
|
|
1384
|
-
const
|
|
1385
|
-
const releaseAction2 = await
|
|
1386
|
-
ctx.
|
|
1549
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1550
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1551
|
+
ctx.created({
|
|
1387
1552
|
data: releaseAction2
|
|
1388
|
-
};
|
|
1553
|
+
});
|
|
1389
1554
|
},
|
|
1390
1555
|
async createMany(ctx) {
|
|
1391
1556
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1393,12 +1558,15 @@ const releaseActionController = {
|
|
|
1393
1558
|
await Promise.all(
|
|
1394
1559
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1395
1560
|
);
|
|
1561
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1396
1562
|
const releaseService = getService("release", { strapi });
|
|
1397
1563
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1398
1564
|
const releaseActions2 = await Promise.all(
|
|
1399
1565
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1400
1566
|
try {
|
|
1401
|
-
const action = await
|
|
1567
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1568
|
+
disableUpdateReleaseStatus: true
|
|
1569
|
+
});
|
|
1402
1570
|
return action;
|
|
1403
1571
|
} catch (error) {
|
|
1404
1572
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1411,43 +1579,54 @@ const releaseActionController = {
|
|
|
1411
1579
|
return releaseActions2;
|
|
1412
1580
|
});
|
|
1413
1581
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1414
|
-
|
|
1582
|
+
if (newReleaseActions.length > 0) {
|
|
1583
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1584
|
+
}
|
|
1585
|
+
ctx.created({
|
|
1415
1586
|
data: newReleaseActions,
|
|
1416
1587
|
meta: {
|
|
1417
1588
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1418
1589
|
totalEntries: releaseActions.length
|
|
1419
1590
|
}
|
|
1420
|
-
};
|
|
1591
|
+
});
|
|
1421
1592
|
},
|
|
1422
1593
|
async findMany(ctx) {
|
|
1423
1594
|
const releaseId = ctx.params.releaseId;
|
|
1424
|
-
const permissionsManager = strapi.admin
|
|
1595
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1425
1596
|
ability: ctx.state.userAbility,
|
|
1426
1597
|
model: RELEASE_ACTION_MODEL_UID
|
|
1427
1598
|
});
|
|
1599
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1600
|
+
if (ctx.query.groupBy) {
|
|
1601
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1602
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1606
|
+
delete ctx.query.groupBy;
|
|
1428
1607
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1429
|
-
const
|
|
1430
|
-
const { results, pagination } = await
|
|
1431
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1608
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1609
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1432
1610
|
...query
|
|
1433
1611
|
});
|
|
1434
1612
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1435
1613
|
if (acc[action.contentType]) {
|
|
1436
1614
|
return acc;
|
|
1437
1615
|
}
|
|
1438
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1616
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1439
1617
|
ability: ctx.state.userAbility,
|
|
1440
1618
|
model: action.contentType
|
|
1441
1619
|
});
|
|
1442
1620
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1443
1621
|
return acc;
|
|
1444
1622
|
}, {});
|
|
1445
|
-
const sanitizedResults = await
|
|
1623
|
+
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1446
1624
|
...action,
|
|
1447
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1625
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1448
1626
|
}));
|
|
1449
|
-
const groupedData = await
|
|
1450
|
-
const contentTypes2 =
|
|
1627
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1628
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1629
|
+
const releaseService = getService("release", { strapi });
|
|
1451
1630
|
const components = await releaseService.getAllComponents();
|
|
1452
1631
|
ctx.body = {
|
|
1453
1632
|
data: groupedData,
|
|
@@ -1463,8 +1642,8 @@ const releaseActionController = {
|
|
|
1463
1642
|
const releaseId = ctx.params.releaseId;
|
|
1464
1643
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1465
1644
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1466
|
-
const
|
|
1467
|
-
const updatedAction = await
|
|
1645
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1646
|
+
const updatedAction = await releaseActionService.update(
|
|
1468
1647
|
actionId,
|
|
1469
1648
|
releaseId,
|
|
1470
1649
|
releaseActionUpdateArgs
|
|
@@ -1476,17 +1655,71 @@ const releaseActionController = {
|
|
|
1476
1655
|
async delete(ctx) {
|
|
1477
1656
|
const actionId = ctx.params.actionId;
|
|
1478
1657
|
const releaseId = ctx.params.releaseId;
|
|
1479
|
-
const
|
|
1480
|
-
const deletedReleaseAction = await
|
|
1658
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1659
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1481
1660
|
ctx.body = {
|
|
1482
1661
|
data: deletedReleaseAction
|
|
1483
1662
|
};
|
|
1484
1663
|
}
|
|
1485
1664
|
};
|
|
1486
|
-
const
|
|
1665
|
+
const SETTINGS_SCHEMA = yup.object().shape({
|
|
1666
|
+
defaultTimezone: yup.string().nullable().default(null)
|
|
1667
|
+
}).required().noUnknown();
|
|
1668
|
+
const validateSettings = validateYupSchema(SETTINGS_SCHEMA);
|
|
1669
|
+
const settingsController = {
|
|
1670
|
+
async find(ctx) {
|
|
1671
|
+
const settingsService = getService("settings", { strapi });
|
|
1672
|
+
const settings2 = await settingsService.find();
|
|
1673
|
+
ctx.body = { data: settings2 };
|
|
1674
|
+
},
|
|
1675
|
+
async update(ctx) {
|
|
1676
|
+
const settingsBody = ctx.request.body;
|
|
1677
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1678
|
+
const settingsService = getService("settings", { strapi });
|
|
1679
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1680
|
+
ctx.body = { data: updatedSettings };
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
const controllers = {
|
|
1684
|
+
release: releaseController,
|
|
1685
|
+
"release-action": releaseActionController,
|
|
1686
|
+
settings: settingsController
|
|
1687
|
+
};
|
|
1487
1688
|
const release = {
|
|
1488
1689
|
type: "admin",
|
|
1489
1690
|
routes: [
|
|
1691
|
+
{
|
|
1692
|
+
method: "GET",
|
|
1693
|
+
path: "/mapEntriesToReleases",
|
|
1694
|
+
handler: "release.mapEntriesToReleases",
|
|
1695
|
+
config: {
|
|
1696
|
+
policies: [
|
|
1697
|
+
"admin::isAuthenticatedAdmin",
|
|
1698
|
+
{
|
|
1699
|
+
name: "admin::hasPermissions",
|
|
1700
|
+
config: {
|
|
1701
|
+
actions: ["plugin::content-releases.read"]
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
]
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
method: "GET",
|
|
1709
|
+
path: "/getByDocumentAttached",
|
|
1710
|
+
handler: "release.findByDocumentAttached",
|
|
1711
|
+
config: {
|
|
1712
|
+
policies: [
|
|
1713
|
+
"admin::isAuthenticatedAdmin",
|
|
1714
|
+
{
|
|
1715
|
+
name: "admin::hasPermissions",
|
|
1716
|
+
config: {
|
|
1717
|
+
actions: ["plugin::content-releases.read"]
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
]
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1490
1723
|
{
|
|
1491
1724
|
method: "POST",
|
|
1492
1725
|
path: "/",
|
|
@@ -1506,7 +1739,7 @@ const release = {
|
|
|
1506
1739
|
{
|
|
1507
1740
|
method: "GET",
|
|
1508
1741
|
path: "/",
|
|
1509
|
-
handler: "release.
|
|
1742
|
+
handler: "release.findPage",
|
|
1510
1743
|
config: {
|
|
1511
1744
|
policies: [
|
|
1512
1745
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1670,13 +1903,50 @@ const releaseAction = {
|
|
|
1670
1903
|
}
|
|
1671
1904
|
]
|
|
1672
1905
|
};
|
|
1906
|
+
const settings = {
|
|
1907
|
+
type: "admin",
|
|
1908
|
+
routes: [
|
|
1909
|
+
{
|
|
1910
|
+
method: "GET",
|
|
1911
|
+
path: "/settings",
|
|
1912
|
+
handler: "settings.find",
|
|
1913
|
+
config: {
|
|
1914
|
+
policies: [
|
|
1915
|
+
"admin::isAuthenticatedAdmin",
|
|
1916
|
+
{
|
|
1917
|
+
name: "admin::hasPermissions",
|
|
1918
|
+
config: {
|
|
1919
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
]
|
|
1923
|
+
}
|
|
1924
|
+
},
|
|
1925
|
+
{
|
|
1926
|
+
method: "PUT",
|
|
1927
|
+
path: "/settings",
|
|
1928
|
+
handler: "settings.update",
|
|
1929
|
+
config: {
|
|
1930
|
+
policies: [
|
|
1931
|
+
"admin::isAuthenticatedAdmin",
|
|
1932
|
+
{
|
|
1933
|
+
name: "admin::hasPermissions",
|
|
1934
|
+
config: {
|
|
1935
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
]
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
]
|
|
1942
|
+
};
|
|
1673
1943
|
const routes = {
|
|
1944
|
+
settings,
|
|
1674
1945
|
release,
|
|
1675
1946
|
"release-action": releaseAction
|
|
1676
1947
|
};
|
|
1677
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1678
1948
|
const getPlugin = () => {
|
|
1679
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1949
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1680
1950
|
return {
|
|
1681
1951
|
register,
|
|
1682
1952
|
bootstrap,
|