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