@strapi/content-releases 0.0.0-next.ca6c7c80ec0b8e77d4b03cd0411e5302de26b8ce → 0.0.0-next.ce84fada19d58a7dfbdd553035e6558f8befcba4
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-gu1aiP6i.mjs → App-BA2xDdy0.mjs} +602 -558
- 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-bpIYXOfu.js → PurchaseContentReleases-Be3acS2L.js} +7 -6
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-3tRbmbY3.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +8 -7
- 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-HrREghh3.js → en-CmYoEnA7.js} +9 -2
- package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
- package/dist/_chunks/{en-ltT1TlKQ.mjs → en-D0yVZFqf.mjs} +9 -2
- 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 +835 -636
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +836 -636
- 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-HjWtUYmc.js +0 -1353
- package/dist/_chunks/App-HjWtUYmc.js.map +0 -1
- package/dist/_chunks/App-gu1aiP6i.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +0 -1
- package/dist/_chunks/en-HrREghh3.js.map +0 -1
- package/dist/_chunks/en-ltT1TlKQ.mjs.map +0 -1
- package/dist/_chunks/index-ZNwxYN8H.js +0 -1335
- package/dist/_chunks/index-ZNwxYN8H.js.map +0 -1
- package/dist/_chunks/index-mvj9PSKd.mjs +0 -1314
- package/dist/_chunks/index-mvj9PSKd.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
|
});
|
|
@@ -253,11 +303,39 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
253
303
|
}
|
|
254
304
|
}
|
|
255
305
|
}
|
|
256
|
-
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
|
+
};
|
|
257
334
|
const register = async ({ strapi: strapi2 }) => {
|
|
258
|
-
if (features
|
|
259
|
-
await strapi2.admin
|
|
260
|
-
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);
|
|
261
339
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
262
340
|
}
|
|
263
341
|
if (strapi2.plugin("graphql")) {
|
|
@@ -266,129 +344,134 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
266
344
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
267
345
|
}
|
|
268
346
|
};
|
|
269
|
-
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
|
+
};
|
|
270
445
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
271
|
-
if (features
|
|
446
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
272
447
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
273
448
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
274
449
|
);
|
|
275
450
|
strapi2.db.lifecycles.subscribe({
|
|
276
451
|
models: contentTypesWithDraftAndPublish,
|
|
277
|
-
async afterDelete(event) {
|
|
278
|
-
try {
|
|
279
|
-
const { model, result } = event;
|
|
280
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
281
|
-
const { id } = result;
|
|
282
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
283
|
-
where: {
|
|
284
|
-
actions: {
|
|
285
|
-
target_type: model.uid,
|
|
286
|
-
target_id: id
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
291
|
-
where: {
|
|
292
|
-
target_type: model.uid,
|
|
293
|
-
target_id: id
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
for (const release2 of releases) {
|
|
297
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
} catch (error) {
|
|
301
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
302
|
-
}
|
|
303
|
-
},
|
|
304
|
-
/**
|
|
305
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
306
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
307
|
-
*/
|
|
308
|
-
async beforeDeleteMany(event) {
|
|
309
|
-
const { model, params } = event;
|
|
310
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
311
|
-
const { where } = params;
|
|
312
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
313
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
452
|
/**
|
|
317
|
-
*
|
|
318
|
-
* 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
|
|
319
454
|
*/
|
|
320
455
|
async afterDeleteMany(event) {
|
|
321
456
|
try {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
target_id: {
|
|
330
|
-
$in: entriesToDelete.map(
|
|
331
|
-
(entry) => entry.id
|
|
332
|
-
)
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
338
|
-
where: {
|
|
339
|
-
target_type: model.uid,
|
|
340
|
-
target_id: {
|
|
341
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
342
|
-
}
|
|
343
|
-
}
|
|
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 }
|
|
344
464
|
});
|
|
345
|
-
for (const release2 of releases) {
|
|
346
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
347
|
-
}
|
|
348
465
|
}
|
|
349
466
|
} catch (error) {
|
|
350
467
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
351
468
|
error
|
|
352
469
|
});
|
|
353
470
|
}
|
|
354
|
-
},
|
|
355
|
-
async afterUpdate(event) {
|
|
356
|
-
try {
|
|
357
|
-
const { model, result } = event;
|
|
358
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
359
|
-
const isEntryValid = await getEntryValidStatus(
|
|
360
|
-
model.uid,
|
|
361
|
-
result,
|
|
362
|
-
{
|
|
363
|
-
strapi: strapi2
|
|
364
|
-
}
|
|
365
|
-
);
|
|
366
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
367
|
-
where: {
|
|
368
|
-
target_type: model.uid,
|
|
369
|
-
target_id: result.id
|
|
370
|
-
},
|
|
371
|
-
data: {
|
|
372
|
-
isEntryValid
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
376
|
-
where: {
|
|
377
|
-
actions: {
|
|
378
|
-
target_type: model.uid,
|
|
379
|
-
target_id: result.id
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
for (const release2 of releases) {
|
|
384
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
} catch (error) {
|
|
388
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
389
|
-
}
|
|
390
471
|
}
|
|
391
472
|
});
|
|
473
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
474
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
392
475
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
393
476
|
strapi2.log.error(
|
|
394
477
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -396,7 +479,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
396
479
|
throw err;
|
|
397
480
|
});
|
|
398
481
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
399
|
-
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
482
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
400
483
|
});
|
|
401
484
|
}
|
|
402
485
|
};
|
|
@@ -480,15 +563,13 @@ const schema = {
|
|
|
480
563
|
enum: ["publish", "unpublish"],
|
|
481
564
|
required: true
|
|
482
565
|
},
|
|
483
|
-
entry: {
|
|
484
|
-
type: "relation",
|
|
485
|
-
relation: "morphToOne",
|
|
486
|
-
configurable: false
|
|
487
|
-
},
|
|
488
566
|
contentType: {
|
|
489
567
|
type: "string",
|
|
490
568
|
required: true
|
|
491
569
|
},
|
|
570
|
+
entryDocumentId: {
|
|
571
|
+
type: "string"
|
|
572
|
+
},
|
|
492
573
|
locale: {
|
|
493
574
|
type: "string"
|
|
494
575
|
},
|
|
@@ -510,18 +591,6 @@ const contentTypes = {
|
|
|
510
591
|
release: release$1,
|
|
511
592
|
"release-action": releaseAction$1
|
|
512
593
|
};
|
|
513
|
-
const getGroupName = (queryValue) => {
|
|
514
|
-
switch (queryValue) {
|
|
515
|
-
case "contentType":
|
|
516
|
-
return "contentType.displayName";
|
|
517
|
-
case "action":
|
|
518
|
-
return "type";
|
|
519
|
-
case "locale":
|
|
520
|
-
return _.getOr("No locale", "locale.name");
|
|
521
|
-
default:
|
|
522
|
-
return "contentType.displayName";
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
594
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
526
595
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
527
596
|
strapi2.eventHub.emit(event, {
|
|
@@ -530,93 +599,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
530
599
|
release: release2
|
|
531
600
|
});
|
|
532
601
|
};
|
|
533
|
-
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
534
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
535
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
536
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
537
|
-
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
538
|
-
try {
|
|
539
|
-
if (actionType === "publish") {
|
|
540
|
-
await entityManagerService.publish(entry, uid);
|
|
541
|
-
} else {
|
|
542
|
-
await entityManagerService.unpublish(entry, uid);
|
|
543
|
-
}
|
|
544
|
-
} catch (error) {
|
|
545
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
546
|
-
;
|
|
547
|
-
else {
|
|
548
|
-
throw error;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
553
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
554
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
555
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
556
|
-
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
557
|
-
filters: {
|
|
558
|
-
id: {
|
|
559
|
-
$in: entriesToPublishIds
|
|
560
|
-
}
|
|
561
|
-
},
|
|
562
|
-
populate
|
|
563
|
-
});
|
|
564
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
565
|
-
filters: {
|
|
566
|
-
id: {
|
|
567
|
-
$in: entriestoUnpublishIds
|
|
568
|
-
}
|
|
569
|
-
},
|
|
570
|
-
populate
|
|
571
|
-
});
|
|
572
|
-
if (entriesToPublish.length > 0) {
|
|
573
|
-
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
574
|
-
}
|
|
575
|
-
if (entriesToUnpublish.length > 0) {
|
|
576
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
577
|
-
}
|
|
578
|
-
};
|
|
579
602
|
const getFormattedActions = async (releaseId) => {
|
|
580
603
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
581
604
|
where: {
|
|
582
605
|
release: {
|
|
583
606
|
id: releaseId
|
|
584
607
|
}
|
|
585
|
-
},
|
|
586
|
-
populate: {
|
|
587
|
-
entry: {
|
|
588
|
-
fields: ["id"]
|
|
589
|
-
}
|
|
590
608
|
}
|
|
591
609
|
});
|
|
592
610
|
if (actions.length === 0) {
|
|
593
611
|
throw new errors.ValidationError("No entries to publish");
|
|
594
612
|
}
|
|
595
|
-
const
|
|
596
|
-
const singleTypeActions = [];
|
|
613
|
+
const formattedActions = {};
|
|
597
614
|
for (const action of actions) {
|
|
598
615
|
const contentTypeUid = action.contentType;
|
|
599
|
-
if (
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
if (action.type === "publish") {
|
|
607
|
-
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
608
|
-
} else {
|
|
609
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
610
|
-
}
|
|
611
|
-
} else {
|
|
612
|
-
singleTypeActions.push({
|
|
613
|
-
uid: contentTypeUid,
|
|
614
|
-
action: action.type,
|
|
615
|
-
id: action.entry.id
|
|
616
|
-
});
|
|
616
|
+
if (!formattedActions[contentTypeUid]) {
|
|
617
|
+
formattedActions[contentTypeUid] = {
|
|
618
|
+
publish: [],
|
|
619
|
+
unpublish: []
|
|
620
|
+
};
|
|
617
621
|
}
|
|
622
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
623
|
+
documentId: action.entryDocumentId,
|
|
624
|
+
locale: action.locale
|
|
625
|
+
});
|
|
618
626
|
}
|
|
619
|
-
return
|
|
627
|
+
return formattedActions;
|
|
620
628
|
};
|
|
621
629
|
return {
|
|
622
630
|
async create(releaseData, { user }) {
|
|
@@ -631,7 +639,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
631
639
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
632
640
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
633
641
|
]);
|
|
634
|
-
const release2 = await strapi2.
|
|
642
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
635
643
|
data: {
|
|
636
644
|
...releaseWithCreatorFields,
|
|
637
645
|
status: "empty"
|
|
@@ -645,107 +653,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
645
653
|
return release2;
|
|
646
654
|
},
|
|
647
655
|
async findOne(id, query = {}) {
|
|
648
|
-
const
|
|
649
|
-
|
|
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 }
|
|
650
660
|
});
|
|
651
661
|
return release2;
|
|
652
662
|
},
|
|
653
663
|
findPage(query) {
|
|
654
|
-
|
|
655
|
-
|
|
664
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
665
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
666
|
+
...dbQuery,
|
|
656
667
|
populate: {
|
|
657
668
|
actions: {
|
|
658
|
-
// @ts-expect-error Ignore missing properties
|
|
659
669
|
count: true
|
|
660
670
|
}
|
|
661
671
|
}
|
|
662
672
|
});
|
|
663
673
|
},
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
670
|
-
where: {
|
|
671
|
-
actions: {
|
|
672
|
-
target_type: contentTypeUid,
|
|
673
|
-
target_id: {
|
|
674
|
-
$in: entries
|
|
675
|
-
}
|
|
676
|
-
},
|
|
677
|
-
releasedAt: {
|
|
678
|
-
$null: true
|
|
679
|
-
}
|
|
680
|
-
},
|
|
681
|
-
populate: {
|
|
682
|
-
// Filter the action to get only the content type entry
|
|
683
|
-
actions: {
|
|
684
|
-
where: {
|
|
685
|
-
target_type: contentTypeUid,
|
|
686
|
-
target_id: {
|
|
687
|
-
$in: entries
|
|
688
|
-
}
|
|
689
|
-
},
|
|
690
|
-
populate: {
|
|
691
|
-
entry: {
|
|
692
|
-
select: ["id"]
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
});
|
|
698
|
-
return releases.map((release2) => {
|
|
699
|
-
if (release2.actions?.length) {
|
|
700
|
-
const actionsForEntry = release2.actions;
|
|
701
|
-
delete release2.actions;
|
|
702
|
-
return {
|
|
703
|
-
...release2,
|
|
704
|
-
actions: actionsForEntry
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
return release2;
|
|
708
|
-
});
|
|
709
|
-
},
|
|
710
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
711
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
712
|
-
where: {
|
|
713
|
-
releasedAt: {
|
|
714
|
-
$null: true
|
|
715
|
-
},
|
|
716
|
-
actions: {
|
|
717
|
-
target_type: contentTypeUid,
|
|
718
|
-
target_id: entryId
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
});
|
|
722
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
723
|
-
where: {
|
|
724
|
-
$or: [
|
|
725
|
-
{
|
|
726
|
-
id: {
|
|
727
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
728
|
-
}
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
actions: null
|
|
732
|
-
}
|
|
733
|
-
],
|
|
734
|
-
releasedAt: {
|
|
735
|
-
$null: true
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
return releases.map((release2) => {
|
|
740
|
-
if (release2.actions?.length) {
|
|
741
|
-
const [actionForEntry] = release2.actions;
|
|
742
|
-
delete release2.actions;
|
|
743
|
-
return {
|
|
744
|
-
...release2,
|
|
745
|
-
action: actionForEntry
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
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
|
|
749
678
|
});
|
|
750
679
|
},
|
|
751
680
|
async update(id, releaseData, { user }) {
|
|
@@ -760,19 +689,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
760
689
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
761
690
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
762
691
|
]);
|
|
763
|
-
const release2 = await strapi2.
|
|
692
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
764
693
|
if (!release2) {
|
|
765
694
|
throw new errors.NotFoundError(`No release found for id ${id}`);
|
|
766
695
|
}
|
|
767
696
|
if (release2.releasedAt) {
|
|
768
697
|
throw new errors.ValidationError("Release already published");
|
|
769
698
|
}
|
|
770
|
-
const updatedRelease = await strapi2.
|
|
771
|
-
|
|
772
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
773
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
774
|
-
*/
|
|
775
|
-
// @ts-expect-error see above
|
|
699
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
700
|
+
where: { id },
|
|
776
701
|
data: releaseWithCreatorFields
|
|
777
702
|
});
|
|
778
703
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -785,130 +710,6 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
785
710
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
786
711
|
return updatedRelease;
|
|
787
712
|
},
|
|
788
|
-
async createAction(releaseId, action) {
|
|
789
|
-
const { validateEntryContentType, validateUniqueEntry } = getService("release-validation", {
|
|
790
|
-
strapi: strapi2
|
|
791
|
-
});
|
|
792
|
-
await Promise.all([
|
|
793
|
-
validateEntryContentType(action.entry.contentType),
|
|
794
|
-
validateUniqueEntry(releaseId, action)
|
|
795
|
-
]);
|
|
796
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
797
|
-
if (!release2) {
|
|
798
|
-
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
799
|
-
}
|
|
800
|
-
if (release2.releasedAt) {
|
|
801
|
-
throw new errors.ValidationError("Release already published");
|
|
802
|
-
}
|
|
803
|
-
const { entry, type } = action;
|
|
804
|
-
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
805
|
-
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
806
|
-
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
807
|
-
data: {
|
|
808
|
-
type,
|
|
809
|
-
contentType: entry.contentType,
|
|
810
|
-
locale: entry.locale,
|
|
811
|
-
isEntryValid,
|
|
812
|
-
entry: {
|
|
813
|
-
id: entry.id,
|
|
814
|
-
__type: entry.contentType,
|
|
815
|
-
__pivot: { field: "entry" }
|
|
816
|
-
},
|
|
817
|
-
release: releaseId
|
|
818
|
-
},
|
|
819
|
-
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
820
|
-
});
|
|
821
|
-
this.updateReleaseStatus(releaseId);
|
|
822
|
-
return releaseAction2;
|
|
823
|
-
},
|
|
824
|
-
async findActions(releaseId, query) {
|
|
825
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
826
|
-
fields: ["id"]
|
|
827
|
-
});
|
|
828
|
-
if (!release2) {
|
|
829
|
-
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
830
|
-
}
|
|
831
|
-
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
832
|
-
...query,
|
|
833
|
-
populate: {
|
|
834
|
-
entry: {
|
|
835
|
-
populate: "*"
|
|
836
|
-
}
|
|
837
|
-
},
|
|
838
|
-
filters: {
|
|
839
|
-
release: releaseId
|
|
840
|
-
}
|
|
841
|
-
});
|
|
842
|
-
},
|
|
843
|
-
async countActions(query) {
|
|
844
|
-
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
845
|
-
},
|
|
846
|
-
async groupActions(actions, groupBy) {
|
|
847
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
848
|
-
if (!acc.includes(action.contentType)) {
|
|
849
|
-
acc.push(action.contentType);
|
|
850
|
-
}
|
|
851
|
-
return acc;
|
|
852
|
-
}, []);
|
|
853
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
854
|
-
contentTypeUids
|
|
855
|
-
);
|
|
856
|
-
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
857
|
-
const formattedData = actions.map((action) => {
|
|
858
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
859
|
-
return {
|
|
860
|
-
...action,
|
|
861
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
862
|
-
contentType: {
|
|
863
|
-
displayName,
|
|
864
|
-
mainFieldValue: action.entry[mainField],
|
|
865
|
-
uid: action.contentType
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
});
|
|
869
|
-
const groupName = getGroupName(groupBy);
|
|
870
|
-
return _.groupBy(groupName)(formattedData);
|
|
871
|
-
},
|
|
872
|
-
async getLocalesDataForActions() {
|
|
873
|
-
if (!strapi2.plugin("i18n")) {
|
|
874
|
-
return {};
|
|
875
|
-
}
|
|
876
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
877
|
-
return allLocales.reduce((acc, locale) => {
|
|
878
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
879
|
-
return acc;
|
|
880
|
-
}, {});
|
|
881
|
-
},
|
|
882
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
883
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
884
|
-
const contentTypesData = {};
|
|
885
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
886
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
887
|
-
uid: contentTypeUid
|
|
888
|
-
});
|
|
889
|
-
contentTypesData[contentTypeUid] = {
|
|
890
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
891
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
return contentTypesData;
|
|
895
|
-
},
|
|
896
|
-
getContentTypeModelsFromActions(actions) {
|
|
897
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
898
|
-
if (!acc.includes(action.contentType)) {
|
|
899
|
-
acc.push(action.contentType);
|
|
900
|
-
}
|
|
901
|
-
return acc;
|
|
902
|
-
}, []);
|
|
903
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
904
|
-
(acc, contentTypeUid) => {
|
|
905
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
906
|
-
return acc;
|
|
907
|
-
},
|
|
908
|
-
{}
|
|
909
|
-
);
|
|
910
|
-
return contentTypeModelsMap;
|
|
911
|
-
},
|
|
912
713
|
async getAllComponents() {
|
|
913
714
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
914
715
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -922,10 +723,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
922
723
|
return componentsMap;
|
|
923
724
|
},
|
|
924
725
|
async delete(releaseId) {
|
|
925
|
-
const release2 = await strapi2.
|
|
726
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
727
|
+
where: { id: releaseId },
|
|
926
728
|
populate: {
|
|
927
729
|
actions: {
|
|
928
|
-
|
|
730
|
+
select: ["id"]
|
|
929
731
|
}
|
|
930
732
|
}
|
|
931
733
|
});
|
|
@@ -943,7 +745,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
943
745
|
}
|
|
944
746
|
}
|
|
945
747
|
});
|
|
946
|
-
await strapi2.
|
|
748
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
749
|
+
where: {
|
|
750
|
+
id: releaseId
|
|
751
|
+
}
|
|
752
|
+
});
|
|
947
753
|
});
|
|
948
754
|
if (release2.scheduledAt) {
|
|
949
755
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -969,22 +775,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
969
775
|
}
|
|
970
776
|
try {
|
|
971
777
|
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
972
|
-
const
|
|
973
|
-
|
|
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
|
+
)
|
|
974
790
|
);
|
|
975
|
-
await strapi2.db.transaction(async () => {
|
|
976
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
977
|
-
await publishSingleTypeAction(uid, action, id);
|
|
978
|
-
}
|
|
979
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
980
|
-
const uid = contentTypeUid;
|
|
981
|
-
await publishCollectionTypeAction(
|
|
982
|
-
uid,
|
|
983
|
-
collectionTypeActions[uid].entriesToPublishIds,
|
|
984
|
-
collectionTypeActions[uid].entriesToUnpublishIds
|
|
985
|
-
);
|
|
986
|
-
}
|
|
987
|
-
});
|
|
988
791
|
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
989
792
|
where: {
|
|
990
793
|
id: releaseId
|
|
@@ -1014,13 +817,226 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1014
817
|
};
|
|
1015
818
|
}
|
|
1016
819
|
});
|
|
1017
|
-
if (error) {
|
|
1018
|
-
throw error;
|
|
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);
|
|
1019
952
|
}
|
|
1020
|
-
return
|
|
953
|
+
return releaseAction2;
|
|
1021
954
|
},
|
|
1022
|
-
async
|
|
1023
|
-
const
|
|
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);
|
|
1017
|
+
},
|
|
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({
|
|
1024
1040
|
where: {
|
|
1025
1041
|
id: actionId,
|
|
1026
1042
|
release: {
|
|
@@ -1029,17 +1045,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1029
1045
|
$null: true
|
|
1030
1046
|
}
|
|
1031
1047
|
}
|
|
1032
|
-
}
|
|
1033
|
-
data: update
|
|
1048
|
+
}
|
|
1034
1049
|
});
|
|
1035
|
-
if (!
|
|
1050
|
+
if (!action) {
|
|
1036
1051
|
throw new errors.NotFoundError(
|
|
1037
1052
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1038
1053
|
);
|
|
1039
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);
|
|
1040
1081
|
return updatedAction;
|
|
1041
1082
|
},
|
|
1042
|
-
async
|
|
1083
|
+
async delete(actionId, releaseId) {
|
|
1043
1084
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1044
1085
|
where: {
|
|
1045
1086
|
id: actionId,
|
|
@@ -1056,51 +1097,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1056
1097
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1057
1098
|
);
|
|
1058
1099
|
}
|
|
1059
|
-
|
|
1100
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1060
1101
|
return deletedAction;
|
|
1061
|
-
},
|
|
1062
|
-
async updateReleaseStatus(releaseId) {
|
|
1063
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
1064
|
-
this.countActions({
|
|
1065
|
-
filters: {
|
|
1066
|
-
release: releaseId
|
|
1067
|
-
}
|
|
1068
|
-
}),
|
|
1069
|
-
this.countActions({
|
|
1070
|
-
filters: {
|
|
1071
|
-
release: releaseId,
|
|
1072
|
-
isEntryValid: false
|
|
1073
|
-
}
|
|
1074
|
-
})
|
|
1075
|
-
]);
|
|
1076
|
-
if (totalActions > 0) {
|
|
1077
|
-
if (invalidActions > 0) {
|
|
1078
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1079
|
-
where: {
|
|
1080
|
-
id: releaseId
|
|
1081
|
-
},
|
|
1082
|
-
data: {
|
|
1083
|
-
status: "blocked"
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1088
|
-
where: {
|
|
1089
|
-
id: releaseId
|
|
1090
|
-
},
|
|
1091
|
-
data: {
|
|
1092
|
-
status: "ready"
|
|
1093
|
-
}
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1097
|
-
where: {
|
|
1098
|
-
id: releaseId
|
|
1099
|
-
},
|
|
1100
|
-
data: {
|
|
1101
|
-
status: "empty"
|
|
1102
|
-
}
|
|
1103
|
-
});
|
|
1104
1102
|
}
|
|
1105
1103
|
};
|
|
1106
1104
|
};
|
|
@@ -1112,37 +1110,43 @@ class AlreadyOnReleaseError extends errors.ApplicationError {
|
|
|
1112
1110
|
}
|
|
1113
1111
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1114
1112
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1115
|
-
const release2 = await strapi2.
|
|
1116
|
-
|
|
1113
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1114
|
+
where: {
|
|
1115
|
+
id: releaseId
|
|
1116
|
+
},
|
|
1117
|
+
populate: {
|
|
1118
|
+
actions: true
|
|
1119
|
+
}
|
|
1117
1120
|
});
|
|
1118
1121
|
if (!release2) {
|
|
1119
1122
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1120
1123
|
}
|
|
1121
1124
|
const isEntryInRelease = release2.actions.some(
|
|
1122
|
-
(action) =>
|
|
1125
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1123
1126
|
);
|
|
1124
1127
|
if (isEntryInRelease) {
|
|
1125
1128
|
throw new AlreadyOnReleaseError(
|
|
1126
|
-
`Entry with
|
|
1129
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1127
1130
|
);
|
|
1128
1131
|
}
|
|
1129
1132
|
},
|
|
1130
|
-
|
|
1133
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1131
1134
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1132
1135
|
if (!contentType) {
|
|
1133
1136
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1134
1137
|
}
|
|
1135
|
-
if (!contentType
|
|
1138
|
+
if (!contentTypes$1.hasDraftAndPublish(contentType)) {
|
|
1136
1139
|
throw new errors.ValidationError(
|
|
1137
1140
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1138
1141
|
);
|
|
1139
1142
|
}
|
|
1143
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1144
|
+
throw new errors.ValidationError("Document id is required for collection type");
|
|
1145
|
+
}
|
|
1140
1146
|
},
|
|
1141
1147
|
async validatePendingReleasesLimit() {
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1144
|
-
EE.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1145
|
-
);
|
|
1148
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1149
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1146
1150
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1147
1151
|
filters: {
|
|
1148
1152
|
releasedAt: {
|
|
@@ -1155,8 +1159,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1155
1159
|
}
|
|
1156
1160
|
},
|
|
1157
1161
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1158
|
-
const pendingReleases = await strapi2.
|
|
1159
|
-
|
|
1162
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1163
|
+
where: {
|
|
1160
1164
|
releasedAt: {
|
|
1161
1165
|
$null: true
|
|
1162
1166
|
},
|
|
@@ -1185,7 +1189,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1185
1189
|
}
|
|
1186
1190
|
const job = scheduleJob(scheduleDate, async () => {
|
|
1187
1191
|
try {
|
|
1188
|
-
await getService("release").publish(releaseId);
|
|
1192
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1189
1193
|
} catch (error) {
|
|
1190
1194
|
}
|
|
1191
1195
|
this.cancel(releaseId);
|
|
@@ -1227,85 +1231,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1227
1231
|
}
|
|
1228
1232
|
};
|
|
1229
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
|
+
};
|
|
1230
1255
|
const services = {
|
|
1231
1256
|
release: createReleaseService,
|
|
1257
|
+
"release-action": createReleaseActionService,
|
|
1232
1258
|
"release-validation": createReleaseValidationService,
|
|
1233
|
-
scheduling: createSchedulingService
|
|
1259
|
+
scheduling: createSchedulingService,
|
|
1260
|
+
settings: createSettingsService
|
|
1234
1261
|
};
|
|
1235
|
-
const RELEASE_SCHEMA = yup.object().shape({
|
|
1236
|
-
name: yup.string().trim().required(),
|
|
1237
|
-
scheduledAt: yup.string().nullable(),
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
otherwise: yup.string().nullable()
|
|
1243
|
-
}),
|
|
1244
|
-
timezone: yup.string().when("isScheduled", {
|
|
1245
|
-
is: true,
|
|
1246
|
-
then: yup.string().required().nullable(),
|
|
1247
|
-
otherwise: yup.string().nullable()
|
|
1248
|
-
}),
|
|
1249
|
-
date: yup.string().when("isScheduled", {
|
|
1250
|
-
is: true,
|
|
1251
|
-
then: yup.string().required().nullable(),
|
|
1252
|
-
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()
|
|
1253
1269
|
})
|
|
1254
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();
|
|
1255
1277
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
1278
|
+
const validatefindByDocumentAttachedParams = validateYupSchema(
|
|
1279
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1280
|
+
);
|
|
1256
1281
|
const releaseController = {
|
|
1257
|
-
|
|
1258
|
-
|
|
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({
|
|
1259
1289
|
ability: ctx.state.userAbility,
|
|
1260
1290
|
model: RELEASE_MODEL_UID
|
|
1261
1291
|
});
|
|
1262
1292
|
await permissionsManager.validateQuery(ctx.query);
|
|
1263
1293
|
const releaseService = getService("release", { strapi });
|
|
1264
|
-
const
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
const
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
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: {
|
|
1279
1317
|
actions: {
|
|
1280
|
-
|
|
1281
|
-
|
|
1318
|
+
fields: ["type"],
|
|
1319
|
+
filters: {
|
|
1320
|
+
contentType,
|
|
1321
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1322
|
+
locale: locale ?? null
|
|
1282
1323
|
}
|
|
1283
1324
|
}
|
|
1284
|
-
}
|
|
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
|
+
}
|
|
1285
1338
|
});
|
|
1286
|
-
const
|
|
1339
|
+
const releases = await releaseService.findMany({
|
|
1287
1340
|
where: {
|
|
1341
|
+
$or: [
|
|
1342
|
+
{
|
|
1343
|
+
id: {
|
|
1344
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
actions: null
|
|
1349
|
+
}
|
|
1350
|
+
],
|
|
1288
1351
|
releasedAt: null
|
|
1289
1352
|
}
|
|
1290
1353
|
});
|
|
1291
|
-
ctx.body = { data
|
|
1354
|
+
ctx.body = { data: releases };
|
|
1292
1355
|
}
|
|
1293
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
|
+
},
|
|
1294
1384
|
async findOne(ctx) {
|
|
1295
1385
|
const id = ctx.params.id;
|
|
1296
1386
|
const releaseService = getService("release", { strapi });
|
|
1387
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1297
1388
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1298
1389
|
if (!release2) {
|
|
1299
1390
|
throw new errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1300
1391
|
}
|
|
1301
|
-
const count = await
|
|
1392
|
+
const count = await releaseActionService.countActions({
|
|
1302
1393
|
filters: {
|
|
1303
1394
|
release: id
|
|
1304
1395
|
}
|
|
1305
1396
|
});
|
|
1306
1397
|
const sanitizedRelease = {
|
|
1307
1398
|
...release2,
|
|
1308
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1399
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1309
1400
|
};
|
|
1310
1401
|
const data = {
|
|
1311
1402
|
...sanitizedRelease,
|
|
@@ -1318,22 +1409,39 @@ const releaseController = {
|
|
|
1318
1409
|
ctx.body = { data };
|
|
1319
1410
|
},
|
|
1320
1411
|
async mapEntriesToReleases(ctx) {
|
|
1321
|
-
const { contentTypeUid,
|
|
1322
|
-
if (!contentTypeUid || !
|
|
1412
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1413
|
+
if (!contentTypeUid || !documentIds) {
|
|
1323
1414
|
throw new errors.ValidationError("Missing required query parameters");
|
|
1324
1415
|
}
|
|
1325
1416
|
const releaseService = getService("release", { strapi });
|
|
1326
|
-
const releasesWithActions = await releaseService.
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
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
|
+
});
|
|
1330
1432
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1331
1433
|
(acc, release2) => {
|
|
1332
1434
|
release2.actions.forEach((action) => {
|
|
1333
|
-
if (
|
|
1334
|
-
|
|
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 }];
|
|
1335
1443
|
} else {
|
|
1336
|
-
acc[action.
|
|
1444
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1337
1445
|
}
|
|
1338
1446
|
});
|
|
1339
1447
|
return acc;
|
|
@@ -1350,13 +1458,13 @@ const releaseController = {
|
|
|
1350
1458
|
await validateRelease(releaseArgs);
|
|
1351
1459
|
const releaseService = getService("release", { strapi });
|
|
1352
1460
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1353
|
-
const permissionsManager = strapi.admin
|
|
1461
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1354
1462
|
ability: ctx.state.userAbility,
|
|
1355
1463
|
model: RELEASE_MODEL_UID
|
|
1356
1464
|
});
|
|
1357
|
-
ctx.
|
|
1465
|
+
ctx.created({
|
|
1358
1466
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1359
|
-
};
|
|
1467
|
+
});
|
|
1360
1468
|
},
|
|
1361
1469
|
async update(ctx) {
|
|
1362
1470
|
const user = ctx.state.user;
|
|
@@ -1365,7 +1473,7 @@ const releaseController = {
|
|
|
1365
1473
|
await validateRelease(releaseArgs);
|
|
1366
1474
|
const releaseService = getService("release", { strapi });
|
|
1367
1475
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1368
|
-
const permissionsManager = strapi.admin
|
|
1476
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1369
1477
|
ability: ctx.state.userAbility,
|
|
1370
1478
|
model: RELEASE_MODEL_UID
|
|
1371
1479
|
});
|
|
@@ -1382,18 +1490,18 @@ const releaseController = {
|
|
|
1382
1490
|
};
|
|
1383
1491
|
},
|
|
1384
1492
|
async publish(ctx) {
|
|
1385
|
-
const user = ctx.state.user;
|
|
1386
1493
|
const id = ctx.params.id;
|
|
1387
1494
|
const releaseService = getService("release", { strapi });
|
|
1388
|
-
const
|
|
1495
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1496
|
+
const release2 = await releaseService.publish(id);
|
|
1389
1497
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1390
|
-
|
|
1498
|
+
releaseActionService.countActions({
|
|
1391
1499
|
filters: {
|
|
1392
1500
|
release: id,
|
|
1393
1501
|
type: "publish"
|
|
1394
1502
|
}
|
|
1395
1503
|
}),
|
|
1396
|
-
|
|
1504
|
+
releaseActionService.countActions({
|
|
1397
1505
|
filters: {
|
|
1398
1506
|
release: id,
|
|
1399
1507
|
type: "unpublish"
|
|
@@ -1411,27 +1519,30 @@ const releaseController = {
|
|
|
1411
1519
|
}
|
|
1412
1520
|
};
|
|
1413
1521
|
const RELEASE_ACTION_SCHEMA = yup$1.object().shape({
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}).required(),
|
|
1522
|
+
contentType: yup$1.string().required(),
|
|
1523
|
+
entryDocumentId: yup$1.strapiID(),
|
|
1524
|
+
locale: yup$1.string(),
|
|
1418
1525
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1419
1526
|
});
|
|
1420
1527
|
const RELEASE_ACTION_UPDATE_SCHEMA = yup$1.object().shape({
|
|
1421
1528
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1422
1529
|
});
|
|
1530
|
+
const FIND_MANY_ACTIONS_PARAMS = yup$1.object().shape({
|
|
1531
|
+
groupBy: yup$1.string().oneOf(["action", "contentType", "locale"])
|
|
1532
|
+
});
|
|
1423
1533
|
const validateReleaseAction = validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1424
1534
|
const validateReleaseActionUpdateSchema = validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1535
|
+
const validateFindManyActionsParams = validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1425
1536
|
const releaseActionController = {
|
|
1426
1537
|
async create(ctx) {
|
|
1427
1538
|
const releaseId = ctx.params.releaseId;
|
|
1428
1539
|
const releaseActionArgs = ctx.request.body;
|
|
1429
1540
|
await validateReleaseAction(releaseActionArgs);
|
|
1430
|
-
const
|
|
1431
|
-
const releaseAction2 = await
|
|
1432
|
-
ctx.
|
|
1541
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1542
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1543
|
+
ctx.created({
|
|
1433
1544
|
data: releaseAction2
|
|
1434
|
-
};
|
|
1545
|
+
});
|
|
1435
1546
|
},
|
|
1436
1547
|
async createMany(ctx) {
|
|
1437
1548
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1439,12 +1550,15 @@ const releaseActionController = {
|
|
|
1439
1550
|
await Promise.all(
|
|
1440
1551
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1441
1552
|
);
|
|
1553
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1442
1554
|
const releaseService = getService("release", { strapi });
|
|
1443
1555
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1444
1556
|
const releaseActions2 = await Promise.all(
|
|
1445
1557
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1446
1558
|
try {
|
|
1447
|
-
const action = await
|
|
1559
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1560
|
+
disableUpdateReleaseStatus: true
|
|
1561
|
+
});
|
|
1448
1562
|
return action;
|
|
1449
1563
|
} catch (error) {
|
|
1450
1564
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1457,43 +1571,54 @@ const releaseActionController = {
|
|
|
1457
1571
|
return releaseActions2;
|
|
1458
1572
|
});
|
|
1459
1573
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1460
|
-
|
|
1574
|
+
if (newReleaseActions.length > 0) {
|
|
1575
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1576
|
+
}
|
|
1577
|
+
ctx.created({
|
|
1461
1578
|
data: newReleaseActions,
|
|
1462
1579
|
meta: {
|
|
1463
1580
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1464
1581
|
totalEntries: releaseActions.length
|
|
1465
1582
|
}
|
|
1466
|
-
};
|
|
1583
|
+
});
|
|
1467
1584
|
},
|
|
1468
1585
|
async findMany(ctx) {
|
|
1469
1586
|
const releaseId = ctx.params.releaseId;
|
|
1470
|
-
const permissionsManager = strapi.admin
|
|
1587
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1471
1588
|
ability: ctx.state.userAbility,
|
|
1472
1589
|
model: RELEASE_ACTION_MODEL_UID
|
|
1473
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;
|
|
1474
1599
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1475
|
-
const
|
|
1476
|
-
const { results, pagination } = await
|
|
1477
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1600
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1601
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1478
1602
|
...query
|
|
1479
1603
|
});
|
|
1480
1604
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1481
1605
|
if (acc[action.contentType]) {
|
|
1482
1606
|
return acc;
|
|
1483
1607
|
}
|
|
1484
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1608
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1485
1609
|
ability: ctx.state.userAbility,
|
|
1486
1610
|
model: action.contentType
|
|
1487
1611
|
});
|
|
1488
1612
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1489
1613
|
return acc;
|
|
1490
1614
|
}, {});
|
|
1491
|
-
const sanitizedResults = await
|
|
1615
|
+
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1492
1616
|
...action,
|
|
1493
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1617
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1494
1618
|
}));
|
|
1495
|
-
const groupedData = await
|
|
1496
|
-
const contentTypes2 =
|
|
1619
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1620
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1621
|
+
const releaseService = getService("release", { strapi });
|
|
1497
1622
|
const components = await releaseService.getAllComponents();
|
|
1498
1623
|
ctx.body = {
|
|
1499
1624
|
data: groupedData,
|
|
@@ -1509,8 +1634,8 @@ const releaseActionController = {
|
|
|
1509
1634
|
const releaseId = ctx.params.releaseId;
|
|
1510
1635
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1511
1636
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1512
|
-
const
|
|
1513
|
-
const updatedAction = await
|
|
1637
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1638
|
+
const updatedAction = await releaseActionService.update(
|
|
1514
1639
|
actionId,
|
|
1515
1640
|
releaseId,
|
|
1516
1641
|
releaseActionUpdateArgs
|
|
@@ -1522,14 +1647,36 @@ const releaseActionController = {
|
|
|
1522
1647
|
async delete(ctx) {
|
|
1523
1648
|
const actionId = ctx.params.actionId;
|
|
1524
1649
|
const releaseId = ctx.params.releaseId;
|
|
1525
|
-
const
|
|
1526
|
-
const deletedReleaseAction = await
|
|
1650
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1651
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1527
1652
|
ctx.body = {
|
|
1528
1653
|
data: deletedReleaseAction
|
|
1529
1654
|
};
|
|
1530
1655
|
}
|
|
1531
1656
|
};
|
|
1532
|
-
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
|
+
};
|
|
1533
1680
|
const release = {
|
|
1534
1681
|
type: "admin",
|
|
1535
1682
|
routes: [
|
|
@@ -1549,6 +1696,22 @@ const release = {
|
|
|
1549
1696
|
]
|
|
1550
1697
|
}
|
|
1551
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
|
+
},
|
|
1552
1715
|
{
|
|
1553
1716
|
method: "POST",
|
|
1554
1717
|
path: "/",
|
|
@@ -1568,7 +1731,7 @@ const release = {
|
|
|
1568
1731
|
{
|
|
1569
1732
|
method: "GET",
|
|
1570
1733
|
path: "/",
|
|
1571
|
-
handler: "release.
|
|
1734
|
+
handler: "release.findPage",
|
|
1572
1735
|
config: {
|
|
1573
1736
|
policies: [
|
|
1574
1737
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1732,13 +1895,50 @@ const releaseAction = {
|
|
|
1732
1895
|
}
|
|
1733
1896
|
]
|
|
1734
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
|
+
};
|
|
1735
1935
|
const routes = {
|
|
1936
|
+
settings,
|
|
1736
1937
|
release,
|
|
1737
1938
|
"release-action": releaseAction
|
|
1738
1939
|
};
|
|
1739
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1740
1940
|
const getPlugin = () => {
|
|
1741
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1941
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1742
1942
|
return {
|
|
1743
1943
|
register,
|
|
1744
1944
|
bootstrap,
|