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