@strapi/content-releases 0.0.0-next.3cc05002fb92029975799c3113971bb5b5198d7c → 0.0.0-next.3fdd03038d558a8190aa7e17574020c5f65395e6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -1
- package/dist/_chunks/App-BKB1esYS.js +1395 -0
- package/dist/_chunks/App-BKB1esYS.js.map +1 -0
- package/dist/_chunks/App-Cne--1Z8.mjs +1374 -0
- package/dist/_chunks/App-Cne--1Z8.mjs.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-YhAPgpG9.js → PurchaseContentReleases-Be3acS2L.js} +8 -7
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-Clm0iACO.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +9 -8
- package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js.map +1 -0
- package/dist/_chunks/{en-faJDuv3q.js → en-CmYoEnA7.js} +19 -3
- package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
- package/dist/_chunks/{en-RdapH-9X.mjs → en-D0yVZFqf.mjs} +19 -3
- package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
- package/dist/_chunks/index-5Odi61vw.js +1381 -0
- package/dist/_chunks/index-5Odi61vw.js.map +1 -0
- package/dist/_chunks/index-Cy7qwpaU.mjs +1362 -0
- package/dist/_chunks/index-Cy7qwpaU.mjs.map +1 -0
- package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
- package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
- package/dist/admin/index.js +1 -15
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +2 -16
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/RelativeTime.d.ts +28 -0
- package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
- package/dist/admin/src/components/ReleaseActionModal.d.ts +24 -0
- package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
- package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
- package/dist/admin/src/components/ReleaseModal.d.ts +17 -0
- package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
- package/dist/admin/src/constants.d.ts +76 -0
- package/dist/admin/src/index.d.ts +3 -0
- package/dist/admin/src/modules/hooks.d.ts +7 -0
- package/dist/admin/src/pages/App.d.ts +1 -0
- package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
- package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
- package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
- package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
- package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
- package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/services/release.d.ts +112 -0
- package/dist/admin/src/store/hooks.d.ts +7 -0
- package/dist/admin/src/utils/api.d.ts +6 -0
- package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
- package/dist/admin/src/utils/time.d.ts +10 -0
- package/dist/admin/src/validation/schemas.d.ts +6 -0
- package/dist/server/index.js +886 -617
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +887 -617
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -0
- package/dist/server/src/constants.d.ts +21 -0
- package/dist/server/src/constants.d.ts.map +1 -0
- package/dist/server/src/content-types/index.d.ts +97 -0
- package/dist/server/src/content-types/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/index.d.ts +48 -0
- package/dist/server/src/content-types/release/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/schema.d.ts +47 -0
- package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/index.d.ts +48 -0
- package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/schema.d.ts +47 -0
- package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
- package/dist/server/src/controllers/index.d.ts +25 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -0
- package/dist/server/src/controllers/release-action.d.ts +10 -0
- package/dist/server/src/controllers/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/release.d.ts +18 -0
- package/dist/server/src/controllers/release.d.ts.map +1 -0
- package/dist/server/src/controllers/settings.d.ts +11 -0
- package/dist/server/src/controllers/settings.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release-action.d.ts +14 -0
- package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release.d.ts +4 -0
- package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/settings.d.ts +3 -0
- package/dist/server/src/controllers/validation/settings.d.ts.map +1 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/destroy.d.ts.map +1 -0
- package/dist/server/src/index.d.ts +2115 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/middlewares/documents.d.ts +6 -0
- package/dist/server/src/middlewares/documents.d.ts.map +1 -0
- package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts +9 -0
- package/dist/server/src/migrations/database/5.0.0-document-id-in-actions.d.ts.map +1 -0
- package/dist/server/src/migrations/index.d.ts +13 -0
- package/dist/server/src/migrations/index.d.ts.map +1 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/register.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts +51 -0
- package/dist/server/src/routes/index.d.ts.map +1 -0
- package/dist/server/src/routes/release-action.d.ts +18 -0
- package/dist/server/src/routes/release-action.d.ts.map +1 -0
- package/dist/server/src/routes/release.d.ts +18 -0
- package/dist/server/src/routes/release.d.ts.map +1 -0
- package/dist/server/src/routes/settings.d.ts +18 -0
- package/dist/server/src/routes/settings.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +1828 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/release-action.d.ts +38 -0
- package/dist/server/src/services/release-action.d.ts.map +1 -0
- package/dist/server/src/services/release.d.ts +31 -0
- package/dist/server/src/services/release.d.ts.map +1 -0
- package/dist/server/src/services/scheduling.d.ts +18 -0
- package/dist/server/src/services/scheduling.d.ts.map +1 -0
- package/dist/server/src/services/settings.d.ts +13 -0
- package/dist/server/src/services/settings.d.ts.map +1 -0
- package/dist/server/src/services/validation.d.ts +18 -0
- package/dist/server/src/services/validation.d.ts.map +1 -0
- package/dist/server/src/utils/index.d.ts +35 -0
- package/dist/server/src/utils/index.d.ts.map +1 -0
- package/dist/shared/contracts/release-actions.d.ts +130 -0
- package/dist/shared/contracts/release-actions.d.ts.map +1 -0
- package/dist/shared/contracts/releases.d.ts +184 -0
- package/dist/shared/contracts/releases.d.ts.map +1 -0
- package/dist/shared/contracts/settings.d.ts +39 -0
- package/dist/shared/contracts/settings.d.ts.map +1 -0
- package/dist/shared/types.d.ts +24 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/package.json +34 -39
- package/dist/_chunks/App-R-kksTW7.mjs +0 -1308
- package/dist/_chunks/App-R-kksTW7.mjs.map +0 -1
- package/dist/_chunks/App-WZHc_d3m.js +0 -1331
- package/dist/_chunks/App-WZHc_d3m.js.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +0 -1
- package/dist/_chunks/en-RdapH-9X.mjs.map +0 -1
- package/dist/_chunks/en-faJDuv3q.js.map +0 -1
- package/dist/_chunks/index-k6fw6RYi.js +0 -1033
- package/dist/_chunks/index-k6fw6RYi.js.map +0 -1
- package/dist/_chunks/index-vpSczx8v.mjs +0 -1012
- package/dist/_chunks/index-vpSczx8v.mjs.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.js
CHANGED
|
@@ -3,7 +3,6 @@ const utils = require("@strapi/utils");
|
|
|
3
3
|
const isEqual = require("lodash/isEqual");
|
|
4
4
|
const lodash = require("lodash");
|
|
5
5
|
const _ = require("lodash/fp");
|
|
6
|
-
const EE = require("@strapi/strapi/dist/utils/ee");
|
|
7
6
|
const nodeSchedule = require("node-schedule");
|
|
8
7
|
const yup = require("yup");
|
|
9
8
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -27,7 +26,6 @@ function _interopNamespace(e) {
|
|
|
27
26
|
}
|
|
28
27
|
const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
|
|
29
28
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
30
|
-
const EE__default = /* @__PURE__ */ _interopDefault(EE);
|
|
31
29
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
32
30
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
33
31
|
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
@@ -73,21 +71,38 @@ const ACTIONS = [
|
|
|
73
71
|
displayName: "Add an entry to a release",
|
|
74
72
|
uid: "create-action",
|
|
75
73
|
pluginName: "content-releases"
|
|
74
|
+
},
|
|
75
|
+
// Settings
|
|
76
|
+
{
|
|
77
|
+
uid: "settings.read",
|
|
78
|
+
section: "settings",
|
|
79
|
+
displayName: "Read",
|
|
80
|
+
category: "content releases",
|
|
81
|
+
subCategory: "options",
|
|
82
|
+
pluginName: "content-releases"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
uid: "settings.update",
|
|
86
|
+
section: "settings",
|
|
87
|
+
displayName: "Edit",
|
|
88
|
+
category: "content releases",
|
|
89
|
+
subCategory: "options",
|
|
90
|
+
pluginName: "content-releases"
|
|
76
91
|
}
|
|
77
92
|
];
|
|
78
93
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
79
94
|
RELEASES_PUBLISH: "releases.publish"
|
|
80
95
|
};
|
|
81
|
-
const getService = (name, { strapi: strapi2 }
|
|
96
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
82
97
|
return strapi2.plugin("content-releases").service(name);
|
|
83
98
|
};
|
|
84
|
-
const
|
|
99
|
+
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi: strapi2 }) => {
|
|
85
100
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
86
|
-
const populate = await populateBuilderService(
|
|
87
|
-
const entry = await
|
|
88
|
-
return entry;
|
|
101
|
+
const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();
|
|
102
|
+
const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi: strapi2 });
|
|
103
|
+
return isEntryValid(contentType, entry, { strapi: strapi2 });
|
|
89
104
|
};
|
|
90
|
-
const
|
|
105
|
+
const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
91
106
|
try {
|
|
92
107
|
await strapi2.entityValidator.validateEntityCreation(
|
|
93
108
|
strapi2.getModel(contentTypeUid),
|
|
@@ -101,6 +116,42 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
101
116
|
return false;
|
|
102
117
|
}
|
|
103
118
|
};
|
|
119
|
+
const getEntry = async ({
|
|
120
|
+
contentType,
|
|
121
|
+
documentId,
|
|
122
|
+
locale,
|
|
123
|
+
populate,
|
|
124
|
+
status = "draft"
|
|
125
|
+
}, { strapi: strapi2 }) => {
|
|
126
|
+
if (documentId) {
|
|
127
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
128
|
+
if (status === "published" && !entry) {
|
|
129
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
130
|
+
}
|
|
131
|
+
return entry;
|
|
132
|
+
}
|
|
133
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
134
|
+
};
|
|
135
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
136
|
+
if (entry.publishedAt) {
|
|
137
|
+
return "published";
|
|
138
|
+
}
|
|
139
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
140
|
+
documentId: entry.documentId,
|
|
141
|
+
locale: entry.locale,
|
|
142
|
+
status: "published",
|
|
143
|
+
fields: ["updatedAt"]
|
|
144
|
+
});
|
|
145
|
+
if (!publishedEntry) {
|
|
146
|
+
return "draft";
|
|
147
|
+
}
|
|
148
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
149
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
150
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
151
|
+
return "modified";
|
|
152
|
+
}
|
|
153
|
+
return "published";
|
|
154
|
+
};
|
|
104
155
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
105
156
|
oldContentTypes,
|
|
106
157
|
contentTypes: contentTypes2
|
|
@@ -122,7 +173,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
122
173
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
123
174
|
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
124
175
|
if (deletedContentTypes.length) {
|
|
125
|
-
await utils.
|
|
176
|
+
await utils.async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
126
177
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
127
178
|
});
|
|
128
179
|
}
|
|
@@ -141,25 +192,27 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
141
192
|
}
|
|
142
193
|
}
|
|
143
194
|
});
|
|
144
|
-
utils.
|
|
195
|
+
utils.async.map(releasesWithoutStatus, async (release2) => {
|
|
145
196
|
const actions = release2.actions;
|
|
146
197
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
147
198
|
for (const action of notValidatedActions) {
|
|
148
199
|
if (action.entry) {
|
|
149
|
-
const
|
|
150
|
-
|
|
200
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
201
|
+
{
|
|
202
|
+
contentType: action.contentType,
|
|
203
|
+
documentId: action.entryDocumentId,
|
|
204
|
+
locale: action.locale
|
|
205
|
+
},
|
|
206
|
+
{ strapi }
|
|
207
|
+
);
|
|
208
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
209
|
+
where: {
|
|
210
|
+
id: action.id
|
|
211
|
+
},
|
|
212
|
+
data: {
|
|
213
|
+
isEntryValid: isEntryValid2
|
|
214
|
+
}
|
|
151
215
|
});
|
|
152
|
-
if (populatedEntry) {
|
|
153
|
-
const isEntryValid = getEntryValidStatus(action.contentType, populatedEntry, { strapi });
|
|
154
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
155
|
-
where: {
|
|
156
|
-
id: action.id
|
|
157
|
-
},
|
|
158
|
-
data: {
|
|
159
|
-
isEntryValid
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
216
|
}
|
|
164
217
|
}
|
|
165
218
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -172,7 +225,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
172
225
|
}
|
|
173
226
|
}
|
|
174
227
|
});
|
|
175
|
-
utils.
|
|
228
|
+
utils.async.map(publishedReleases, async (release2) => {
|
|
176
229
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
177
230
|
where: {
|
|
178
231
|
id: release2.id
|
|
@@ -189,7 +242,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
189
242
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
190
243
|
);
|
|
191
244
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
192
|
-
utils.
|
|
245
|
+
utils.async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
193
246
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
194
247
|
const contentType = contentTypes2[contentTypeUID];
|
|
195
248
|
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -202,30 +255,30 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
202
255
|
release: true
|
|
203
256
|
}
|
|
204
257
|
});
|
|
205
|
-
await utils.
|
|
206
|
-
if (action.entry && action.release) {
|
|
207
|
-
const
|
|
208
|
-
|
|
258
|
+
await utils.async.map(actions, async (action) => {
|
|
259
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
260
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
261
|
+
{
|
|
262
|
+
contentType: contentTypeUID,
|
|
263
|
+
documentId: action.entryDocumentId,
|
|
264
|
+
locale: action.locale
|
|
265
|
+
},
|
|
266
|
+
{ strapi }
|
|
267
|
+
);
|
|
268
|
+
releasesAffected.add(action.release.id);
|
|
269
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
270
|
+
where: {
|
|
271
|
+
id: action.id
|
|
272
|
+
},
|
|
273
|
+
data: {
|
|
274
|
+
isEntryValid: isEntryValid2
|
|
275
|
+
}
|
|
209
276
|
});
|
|
210
|
-
if (populatedEntry) {
|
|
211
|
-
const isEntryValid = await getEntryValidStatus(contentTypeUID, populatedEntry, {
|
|
212
|
-
strapi
|
|
213
|
-
});
|
|
214
|
-
releasesAffected.add(action.release.id);
|
|
215
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
216
|
-
where: {
|
|
217
|
-
id: action.id
|
|
218
|
-
},
|
|
219
|
-
data: {
|
|
220
|
-
isEntryValid
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
277
|
}
|
|
225
278
|
});
|
|
226
279
|
}
|
|
227
280
|
}).then(() => {
|
|
228
|
-
utils.
|
|
281
|
+
utils.async.map(releasesAffected, async (releaseId) => {
|
|
229
282
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
230
283
|
});
|
|
231
284
|
});
|
|
@@ -235,13 +288,16 @@ async function disableContentTypeLocalized({ oldContentTypes, contentTypes: cont
|
|
|
235
288
|
if (!oldContentTypes) {
|
|
236
289
|
return;
|
|
237
290
|
}
|
|
291
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
292
|
+
if (!i18nPlugin) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
238
295
|
for (const uid in contentTypes2) {
|
|
239
296
|
if (!oldContentTypes[uid]) {
|
|
240
297
|
continue;
|
|
241
298
|
}
|
|
242
299
|
const oldContentType = oldContentTypes[uid];
|
|
243
300
|
const contentType = contentTypes2[uid];
|
|
244
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
245
301
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
246
302
|
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
247
303
|
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
@@ -254,13 +310,16 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
254
310
|
if (!oldContentTypes) {
|
|
255
311
|
return;
|
|
256
312
|
}
|
|
313
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
314
|
+
if (!i18nPlugin) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
257
317
|
for (const uid in contentTypes2) {
|
|
258
318
|
if (!oldContentTypes[uid]) {
|
|
259
319
|
continue;
|
|
260
320
|
}
|
|
261
321
|
const oldContentType = oldContentTypes[uid];
|
|
262
322
|
const contentType = contentTypes2[uid];
|
|
263
|
-
const i18nPlugin = strapi.plugin("i18n");
|
|
264
323
|
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
265
324
|
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
266
325
|
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
@@ -271,11 +330,43 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
271
330
|
}
|
|
272
331
|
}
|
|
273
332
|
}
|
|
274
|
-
const
|
|
333
|
+
const addEntryDocumentToReleaseActions = {
|
|
334
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
335
|
+
async up(trx, db) {
|
|
336
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
337
|
+
if (!hasTable) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
341
|
+
if (hasPolymorphicColumn) {
|
|
342
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
343
|
+
"strapi_release_actions",
|
|
344
|
+
"entry_document_id"
|
|
345
|
+
);
|
|
346
|
+
if (!hasEntryDocumentIdColumn) {
|
|
347
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
348
|
+
table.string("entry_document_id");
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
352
|
+
utils.async.map(releaseActions, async (action) => {
|
|
353
|
+
const { target_type, target_id } = action;
|
|
354
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
355
|
+
if (entry) {
|
|
356
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
async down() {
|
|
362
|
+
throw new Error("not implemented");
|
|
363
|
+
}
|
|
364
|
+
};
|
|
275
365
|
const register = async ({ strapi: strapi2 }) => {
|
|
276
|
-
if (features
|
|
277
|
-
await strapi2.admin
|
|
278
|
-
strapi2.
|
|
366
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
367
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
368
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
369
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
279
370
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
280
371
|
}
|
|
281
372
|
if (strapi2.plugin("graphql")) {
|
|
@@ -284,129 +375,134 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
284
375
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
285
376
|
}
|
|
286
377
|
};
|
|
287
|
-
const
|
|
378
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
379
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
380
|
+
where: {
|
|
381
|
+
actions: {
|
|
382
|
+
contentType,
|
|
383
|
+
entryDocumentId: entry.documentId,
|
|
384
|
+
locale: entry.locale
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
389
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
390
|
+
where: {
|
|
391
|
+
contentType,
|
|
392
|
+
entryDocumentId: entry.documentId,
|
|
393
|
+
locale: entry.locale
|
|
394
|
+
},
|
|
395
|
+
data: {
|
|
396
|
+
isEntryValid: entryStatus
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
for (const release2 of releases) {
|
|
400
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
404
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
405
|
+
where: {
|
|
406
|
+
actions: params
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
410
|
+
where: params
|
|
411
|
+
});
|
|
412
|
+
for (const release2 of releases) {
|
|
413
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
417
|
+
if (ctx.action !== "delete") {
|
|
418
|
+
return next();
|
|
419
|
+
}
|
|
420
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
421
|
+
return next();
|
|
422
|
+
}
|
|
423
|
+
const contentType = ctx.contentType.uid;
|
|
424
|
+
const { documentId, locale } = ctx.params;
|
|
425
|
+
const result = await next();
|
|
426
|
+
if (!result) {
|
|
427
|
+
return result;
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
431
|
+
contentType,
|
|
432
|
+
entryDocumentId: documentId,
|
|
433
|
+
...locale !== "*" && { locale }
|
|
434
|
+
});
|
|
435
|
+
} catch (error) {
|
|
436
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
437
|
+
error
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
441
|
+
};
|
|
442
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
443
|
+
if (ctx.action !== "update") {
|
|
444
|
+
return next();
|
|
445
|
+
}
|
|
446
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
447
|
+
return next();
|
|
448
|
+
}
|
|
449
|
+
const contentType = ctx.contentType.uid;
|
|
450
|
+
const result = await next();
|
|
451
|
+
if (!result) {
|
|
452
|
+
return result;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
458
|
+
error
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return result;
|
|
462
|
+
};
|
|
463
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
464
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
465
|
+
where: {
|
|
466
|
+
actions: params
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
470
|
+
where: params
|
|
471
|
+
});
|
|
472
|
+
for (const release2 of releases) {
|
|
473
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
288
476
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
289
|
-
if (features
|
|
477
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
290
478
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
291
479
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
292
480
|
);
|
|
293
481
|
strapi2.db.lifecycles.subscribe({
|
|
294
482
|
models: contentTypesWithDraftAndPublish,
|
|
295
|
-
async afterDelete(event) {
|
|
296
|
-
try {
|
|
297
|
-
const { model, result } = event;
|
|
298
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
299
|
-
const { id } = result;
|
|
300
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
301
|
-
where: {
|
|
302
|
-
actions: {
|
|
303
|
-
target_type: model.uid,
|
|
304
|
-
target_id: id
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
309
|
-
where: {
|
|
310
|
-
target_type: model.uid,
|
|
311
|
-
target_id: id
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
for (const release2 of releases) {
|
|
315
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
} catch (error) {
|
|
319
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
483
|
/**
|
|
323
|
-
* deleteMany
|
|
324
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
325
|
-
*/
|
|
326
|
-
async beforeDeleteMany(event) {
|
|
327
|
-
const { model, params } = event;
|
|
328
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
329
|
-
const { where } = params;
|
|
330
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
331
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
/**
|
|
335
|
-
* We delete the release actions related to deleted entries
|
|
336
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
484
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
337
485
|
*/
|
|
338
486
|
async afterDeleteMany(event) {
|
|
339
487
|
try {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
target_id: {
|
|
348
|
-
$in: entriesToDelete.map(
|
|
349
|
-
(entry) => entry.id
|
|
350
|
-
)
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
356
|
-
where: {
|
|
357
|
-
target_type: model.uid,
|
|
358
|
-
target_id: {
|
|
359
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
360
|
-
}
|
|
361
|
-
}
|
|
488
|
+
const model = strapi2.getModel(event.model.uid);
|
|
489
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
490
|
+
const { where } = event.params;
|
|
491
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
492
|
+
contentType: model.uid,
|
|
493
|
+
locale: where?.locale ?? null,
|
|
494
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
362
495
|
});
|
|
363
|
-
for (const release2 of releases) {
|
|
364
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
365
|
-
}
|
|
366
496
|
}
|
|
367
497
|
} catch (error) {
|
|
368
498
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
369
499
|
error
|
|
370
500
|
});
|
|
371
501
|
}
|
|
372
|
-
},
|
|
373
|
-
async afterUpdate(event) {
|
|
374
|
-
try {
|
|
375
|
-
const { model, result } = event;
|
|
376
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
377
|
-
const isEntryValid = await getEntryValidStatus(
|
|
378
|
-
model.uid,
|
|
379
|
-
result,
|
|
380
|
-
{
|
|
381
|
-
strapi: strapi2
|
|
382
|
-
}
|
|
383
|
-
);
|
|
384
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
385
|
-
where: {
|
|
386
|
-
target_type: model.uid,
|
|
387
|
-
target_id: result.id
|
|
388
|
-
},
|
|
389
|
-
data: {
|
|
390
|
-
isEntryValid
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
394
|
-
where: {
|
|
395
|
-
actions: {
|
|
396
|
-
target_type: model.uid,
|
|
397
|
-
target_id: result.id
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
for (const release2 of releases) {
|
|
402
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
} catch (error) {
|
|
406
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
407
|
-
}
|
|
408
502
|
}
|
|
409
503
|
});
|
|
504
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
505
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
410
506
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
411
507
|
strapi2.log.error(
|
|
412
508
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -414,7 +510,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
414
510
|
throw err;
|
|
415
511
|
});
|
|
416
512
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
417
|
-
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
513
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
418
514
|
});
|
|
419
515
|
}
|
|
420
516
|
};
|
|
@@ -498,15 +594,13 @@ const schema = {
|
|
|
498
594
|
enum: ["publish", "unpublish"],
|
|
499
595
|
required: true
|
|
500
596
|
},
|
|
501
|
-
entry: {
|
|
502
|
-
type: "relation",
|
|
503
|
-
relation: "morphToOne",
|
|
504
|
-
configurable: false
|
|
505
|
-
},
|
|
506
597
|
contentType: {
|
|
507
598
|
type: "string",
|
|
508
599
|
required: true
|
|
509
600
|
},
|
|
601
|
+
entryDocumentId: {
|
|
602
|
+
type: "string"
|
|
603
|
+
},
|
|
510
604
|
locale: {
|
|
511
605
|
type: "string"
|
|
512
606
|
},
|
|
@@ -528,18 +622,6 @@ const contentTypes = {
|
|
|
528
622
|
release: release$1,
|
|
529
623
|
"release-action": releaseAction$1
|
|
530
624
|
};
|
|
531
|
-
const getGroupName = (queryValue) => {
|
|
532
|
-
switch (queryValue) {
|
|
533
|
-
case "contentType":
|
|
534
|
-
return "contentType.displayName";
|
|
535
|
-
case "action":
|
|
536
|
-
return "type";
|
|
537
|
-
case "locale":
|
|
538
|
-
return ___default.default.getOr("No locale", "locale.name");
|
|
539
|
-
default:
|
|
540
|
-
return "contentType.displayName";
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
625
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
544
626
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
545
627
|
strapi2.eventHub.emit(event, {
|
|
@@ -548,93 +630,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
548
630
|
release: release2
|
|
549
631
|
});
|
|
550
632
|
};
|
|
551
|
-
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
552
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
553
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
554
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
555
|
-
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
556
|
-
try {
|
|
557
|
-
if (actionType === "publish") {
|
|
558
|
-
await entityManagerService.publish(entry, uid);
|
|
559
|
-
} else {
|
|
560
|
-
await entityManagerService.unpublish(entry, uid);
|
|
561
|
-
}
|
|
562
|
-
} catch (error) {
|
|
563
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
564
|
-
;
|
|
565
|
-
else {
|
|
566
|
-
throw error;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
|
-
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
571
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
572
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
573
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
574
|
-
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
575
|
-
filters: {
|
|
576
|
-
id: {
|
|
577
|
-
$in: entriesToPublishIds
|
|
578
|
-
}
|
|
579
|
-
},
|
|
580
|
-
populate
|
|
581
|
-
});
|
|
582
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
583
|
-
filters: {
|
|
584
|
-
id: {
|
|
585
|
-
$in: entriestoUnpublishIds
|
|
586
|
-
}
|
|
587
|
-
},
|
|
588
|
-
populate
|
|
589
|
-
});
|
|
590
|
-
if (entriesToPublish.length > 0) {
|
|
591
|
-
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
592
|
-
}
|
|
593
|
-
if (entriesToUnpublish.length > 0) {
|
|
594
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
595
|
-
}
|
|
596
|
-
};
|
|
597
633
|
const getFormattedActions = async (releaseId) => {
|
|
598
634
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
599
635
|
where: {
|
|
600
636
|
release: {
|
|
601
637
|
id: releaseId
|
|
602
638
|
}
|
|
603
|
-
},
|
|
604
|
-
populate: {
|
|
605
|
-
entry: {
|
|
606
|
-
fields: ["id"]
|
|
607
|
-
}
|
|
608
639
|
}
|
|
609
640
|
});
|
|
610
641
|
if (actions.length === 0) {
|
|
611
642
|
throw new utils.errors.ValidationError("No entries to publish");
|
|
612
643
|
}
|
|
613
|
-
const
|
|
614
|
-
const singleTypeActions = [];
|
|
644
|
+
const formattedActions = {};
|
|
615
645
|
for (const action of actions) {
|
|
616
646
|
const contentTypeUid = action.contentType;
|
|
617
|
-
if (
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
if (action.type === "publish") {
|
|
625
|
-
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
626
|
-
} else {
|
|
627
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
628
|
-
}
|
|
629
|
-
} else {
|
|
630
|
-
singleTypeActions.push({
|
|
631
|
-
uid: contentTypeUid,
|
|
632
|
-
action: action.type,
|
|
633
|
-
id: action.entry.id
|
|
634
|
-
});
|
|
647
|
+
if (!formattedActions[contentTypeUid]) {
|
|
648
|
+
formattedActions[contentTypeUid] = {
|
|
649
|
+
publish: [],
|
|
650
|
+
unpublish: []
|
|
651
|
+
};
|
|
635
652
|
}
|
|
653
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
654
|
+
documentId: action.entryDocumentId,
|
|
655
|
+
locale: action.locale
|
|
656
|
+
});
|
|
636
657
|
}
|
|
637
|
-
return
|
|
658
|
+
return formattedActions;
|
|
638
659
|
};
|
|
639
660
|
return {
|
|
640
661
|
async create(releaseData, { user }) {
|
|
@@ -649,7 +670,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
649
670
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
650
671
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
651
672
|
]);
|
|
652
|
-
const release2 = await strapi2.
|
|
673
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
653
674
|
data: {
|
|
654
675
|
...releaseWithCreatorFields,
|
|
655
676
|
status: "empty"
|
|
@@ -663,94 +684,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
663
684
|
return release2;
|
|
664
685
|
},
|
|
665
686
|
async findOne(id, query = {}) {
|
|
666
|
-
const
|
|
667
|
-
|
|
687
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
688
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
689
|
+
...dbQuery,
|
|
690
|
+
where: { id }
|
|
668
691
|
});
|
|
669
692
|
return release2;
|
|
670
693
|
},
|
|
671
694
|
findPage(query) {
|
|
672
|
-
|
|
673
|
-
|
|
695
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
696
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
697
|
+
...dbQuery,
|
|
674
698
|
populate: {
|
|
675
699
|
actions: {
|
|
676
|
-
// @ts-expect-error Ignore missing properties
|
|
677
700
|
count: true
|
|
678
701
|
}
|
|
679
702
|
}
|
|
680
703
|
});
|
|
681
704
|
},
|
|
682
|
-
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
target_type: contentTypeUid,
|
|
687
|
-
target_id: entryId
|
|
688
|
-
},
|
|
689
|
-
releasedAt: {
|
|
690
|
-
$null: true
|
|
691
|
-
}
|
|
692
|
-
},
|
|
693
|
-
populate: {
|
|
694
|
-
// Filter the action to get only the content type entry
|
|
695
|
-
actions: {
|
|
696
|
-
where: {
|
|
697
|
-
target_type: contentTypeUid,
|
|
698
|
-
target_id: entryId
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
return releases.map((release2) => {
|
|
704
|
-
if (release2.actions?.length) {
|
|
705
|
-
const [actionForEntry] = release2.actions;
|
|
706
|
-
delete release2.actions;
|
|
707
|
-
return {
|
|
708
|
-
...release2,
|
|
709
|
-
action: actionForEntry
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
return release2;
|
|
713
|
-
});
|
|
714
|
-
},
|
|
715
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
716
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
717
|
-
where: {
|
|
718
|
-
releasedAt: {
|
|
719
|
-
$null: true
|
|
720
|
-
},
|
|
721
|
-
actions: {
|
|
722
|
-
target_type: contentTypeUid,
|
|
723
|
-
target_id: entryId
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
});
|
|
727
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
728
|
-
where: {
|
|
729
|
-
$or: [
|
|
730
|
-
{
|
|
731
|
-
id: {
|
|
732
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
733
|
-
}
|
|
734
|
-
},
|
|
735
|
-
{
|
|
736
|
-
actions: null
|
|
737
|
-
}
|
|
738
|
-
],
|
|
739
|
-
releasedAt: {
|
|
740
|
-
$null: true
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
});
|
|
744
|
-
return releases.map((release2) => {
|
|
745
|
-
if (release2.actions?.length) {
|
|
746
|
-
const [actionForEntry] = release2.actions;
|
|
747
|
-
delete release2.actions;
|
|
748
|
-
return {
|
|
749
|
-
...release2,
|
|
750
|
-
action: actionForEntry
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
return release2;
|
|
705
|
+
findMany(query) {
|
|
706
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
707
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
708
|
+
...dbQuery
|
|
754
709
|
});
|
|
755
710
|
},
|
|
756
711
|
async update(id, releaseData, { user }) {
|
|
@@ -765,19 +720,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
765
720
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
766
721
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
767
722
|
]);
|
|
768
|
-
const release2 = await strapi2.
|
|
723
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
769
724
|
if (!release2) {
|
|
770
725
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
771
726
|
}
|
|
772
727
|
if (release2.releasedAt) {
|
|
773
728
|
throw new utils.errors.ValidationError("Release already published");
|
|
774
729
|
}
|
|
775
|
-
const updatedRelease = await strapi2.
|
|
776
|
-
|
|
777
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
778
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
779
|
-
*/
|
|
780
|
-
// @ts-expect-error see above
|
|
730
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
731
|
+
where: { id },
|
|
781
732
|
data: releaseWithCreatorFields
|
|
782
733
|
});
|
|
783
734
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -790,130 +741,6 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
790
741
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
791
742
|
return updatedRelease;
|
|
792
743
|
},
|
|
793
|
-
async createAction(releaseId, action) {
|
|
794
|
-
const { validateEntryContentType, validateUniqueEntry } = getService("release-validation", {
|
|
795
|
-
strapi: strapi2
|
|
796
|
-
});
|
|
797
|
-
await Promise.all([
|
|
798
|
-
validateEntryContentType(action.entry.contentType),
|
|
799
|
-
validateUniqueEntry(releaseId, action)
|
|
800
|
-
]);
|
|
801
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
802
|
-
if (!release2) {
|
|
803
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
804
|
-
}
|
|
805
|
-
if (release2.releasedAt) {
|
|
806
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
807
|
-
}
|
|
808
|
-
const { entry, type } = action;
|
|
809
|
-
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
810
|
-
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
811
|
-
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
812
|
-
data: {
|
|
813
|
-
type,
|
|
814
|
-
contentType: entry.contentType,
|
|
815
|
-
locale: entry.locale,
|
|
816
|
-
isEntryValid,
|
|
817
|
-
entry: {
|
|
818
|
-
id: entry.id,
|
|
819
|
-
__type: entry.contentType,
|
|
820
|
-
__pivot: { field: "entry" }
|
|
821
|
-
},
|
|
822
|
-
release: releaseId
|
|
823
|
-
},
|
|
824
|
-
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
825
|
-
});
|
|
826
|
-
this.updateReleaseStatus(releaseId);
|
|
827
|
-
return releaseAction2;
|
|
828
|
-
},
|
|
829
|
-
async findActions(releaseId, query) {
|
|
830
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
831
|
-
fields: ["id"]
|
|
832
|
-
});
|
|
833
|
-
if (!release2) {
|
|
834
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
835
|
-
}
|
|
836
|
-
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
837
|
-
...query,
|
|
838
|
-
populate: {
|
|
839
|
-
entry: {
|
|
840
|
-
populate: "*"
|
|
841
|
-
}
|
|
842
|
-
},
|
|
843
|
-
filters: {
|
|
844
|
-
release: releaseId
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
},
|
|
848
|
-
async countActions(query) {
|
|
849
|
-
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
850
|
-
},
|
|
851
|
-
async groupActions(actions, groupBy) {
|
|
852
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
853
|
-
if (!acc.includes(action.contentType)) {
|
|
854
|
-
acc.push(action.contentType);
|
|
855
|
-
}
|
|
856
|
-
return acc;
|
|
857
|
-
}, []);
|
|
858
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
859
|
-
contentTypeUids
|
|
860
|
-
);
|
|
861
|
-
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
862
|
-
const formattedData = actions.map((action) => {
|
|
863
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
864
|
-
return {
|
|
865
|
-
...action,
|
|
866
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
867
|
-
contentType: {
|
|
868
|
-
displayName,
|
|
869
|
-
mainFieldValue: action.entry[mainField],
|
|
870
|
-
uid: action.contentType
|
|
871
|
-
}
|
|
872
|
-
};
|
|
873
|
-
});
|
|
874
|
-
const groupName = getGroupName(groupBy);
|
|
875
|
-
return ___default.default.groupBy(groupName)(formattedData);
|
|
876
|
-
},
|
|
877
|
-
async getLocalesDataForActions() {
|
|
878
|
-
if (!strapi2.plugin("i18n")) {
|
|
879
|
-
return {};
|
|
880
|
-
}
|
|
881
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
882
|
-
return allLocales.reduce((acc, locale) => {
|
|
883
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
884
|
-
return acc;
|
|
885
|
-
}, {});
|
|
886
|
-
},
|
|
887
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
888
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
889
|
-
const contentTypesData = {};
|
|
890
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
891
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
892
|
-
uid: contentTypeUid
|
|
893
|
-
});
|
|
894
|
-
contentTypesData[contentTypeUid] = {
|
|
895
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
896
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
return contentTypesData;
|
|
900
|
-
},
|
|
901
|
-
getContentTypeModelsFromActions(actions) {
|
|
902
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
903
|
-
if (!acc.includes(action.contentType)) {
|
|
904
|
-
acc.push(action.contentType);
|
|
905
|
-
}
|
|
906
|
-
return acc;
|
|
907
|
-
}, []);
|
|
908
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
909
|
-
(acc, contentTypeUid) => {
|
|
910
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
911
|
-
return acc;
|
|
912
|
-
},
|
|
913
|
-
{}
|
|
914
|
-
);
|
|
915
|
-
return contentTypeModelsMap;
|
|
916
|
-
},
|
|
917
744
|
async getAllComponents() {
|
|
918
745
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
919
746
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -927,10 +754,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
927
754
|
return componentsMap;
|
|
928
755
|
},
|
|
929
756
|
async delete(releaseId) {
|
|
930
|
-
const release2 = await strapi2.
|
|
757
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
758
|
+
where: { id: releaseId },
|
|
931
759
|
populate: {
|
|
932
760
|
actions: {
|
|
933
|
-
|
|
761
|
+
select: ["id"]
|
|
934
762
|
}
|
|
935
763
|
}
|
|
936
764
|
});
|
|
@@ -948,7 +776,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
948
776
|
}
|
|
949
777
|
}
|
|
950
778
|
});
|
|
951
|
-
await strapi2.
|
|
779
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
780
|
+
where: {
|
|
781
|
+
id: releaseId
|
|
782
|
+
}
|
|
783
|
+
});
|
|
952
784
|
});
|
|
953
785
|
if (release2.scheduledAt) {
|
|
954
786
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -974,22 +806,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
974
806
|
}
|
|
975
807
|
try {
|
|
976
808
|
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
977
|
-
const
|
|
978
|
-
|
|
809
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
810
|
+
await strapi2.db.transaction(
|
|
811
|
+
async () => Promise.all(
|
|
812
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
813
|
+
const contentType = contentTypeUid;
|
|
814
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
815
|
+
return Promise.all([
|
|
816
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
817
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
818
|
+
]);
|
|
819
|
+
})
|
|
820
|
+
)
|
|
979
821
|
);
|
|
980
|
-
await strapi2.db.transaction(async () => {
|
|
981
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
982
|
-
await publishSingleTypeAction(uid, action, id);
|
|
983
|
-
}
|
|
984
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
985
|
-
const uid = contentTypeUid;
|
|
986
|
-
await publishCollectionTypeAction(
|
|
987
|
-
uid,
|
|
988
|
-
collectionTypeActions[uid].entriesToPublishIds,
|
|
989
|
-
collectionTypeActions[uid].entriesToUnpublishIds
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
|
-
});
|
|
993
822
|
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
994
823
|
where: {
|
|
995
824
|
id: releaseId
|
|
@@ -1019,13 +848,226 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1019
848
|
};
|
|
1020
849
|
}
|
|
1021
850
|
});
|
|
1022
|
-
if (error) {
|
|
1023
|
-
throw error;
|
|
1024
|
-
}
|
|
1025
|
-
return release2;
|
|
851
|
+
if (error instanceof Error) {
|
|
852
|
+
throw error;
|
|
853
|
+
}
|
|
854
|
+
return release2;
|
|
855
|
+
},
|
|
856
|
+
async updateReleaseStatus(releaseId) {
|
|
857
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
858
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
859
|
+
releaseActionService.countActions({
|
|
860
|
+
filters: {
|
|
861
|
+
release: releaseId
|
|
862
|
+
}
|
|
863
|
+
}),
|
|
864
|
+
releaseActionService.countActions({
|
|
865
|
+
filters: {
|
|
866
|
+
release: releaseId,
|
|
867
|
+
isEntryValid: false
|
|
868
|
+
}
|
|
869
|
+
})
|
|
870
|
+
]);
|
|
871
|
+
if (totalActions > 0) {
|
|
872
|
+
if (invalidActions > 0) {
|
|
873
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
874
|
+
where: {
|
|
875
|
+
id: releaseId
|
|
876
|
+
},
|
|
877
|
+
data: {
|
|
878
|
+
status: "blocked"
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
883
|
+
where: {
|
|
884
|
+
id: releaseId
|
|
885
|
+
},
|
|
886
|
+
data: {
|
|
887
|
+
status: "ready"
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
892
|
+
where: {
|
|
893
|
+
id: releaseId
|
|
894
|
+
},
|
|
895
|
+
data: {
|
|
896
|
+
status: "empty"
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
};
|
|
902
|
+
const getGroupName = (queryValue) => {
|
|
903
|
+
switch (queryValue) {
|
|
904
|
+
case "contentType":
|
|
905
|
+
return "contentType.displayName";
|
|
906
|
+
case "type":
|
|
907
|
+
return "type";
|
|
908
|
+
case "locale":
|
|
909
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
910
|
+
default:
|
|
911
|
+
return "contentType.displayName";
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
915
|
+
const getLocalesDataForActions = async () => {
|
|
916
|
+
if (!strapi2.plugin("i18n")) {
|
|
917
|
+
return {};
|
|
918
|
+
}
|
|
919
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
920
|
+
return allLocales.reduce((acc, locale) => {
|
|
921
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
922
|
+
return acc;
|
|
923
|
+
}, {});
|
|
924
|
+
};
|
|
925
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
926
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
927
|
+
const contentTypesData = {};
|
|
928
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
929
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
930
|
+
uid: contentTypeUid
|
|
931
|
+
});
|
|
932
|
+
contentTypesData[contentTypeUid] = {
|
|
933
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
934
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
return contentTypesData;
|
|
938
|
+
};
|
|
939
|
+
return {
|
|
940
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
941
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
942
|
+
strapi: strapi2
|
|
943
|
+
});
|
|
944
|
+
await Promise.all([
|
|
945
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
946
|
+
validateUniqueEntry(releaseId, action)
|
|
947
|
+
]);
|
|
948
|
+
const model = strapi2.contentType(action.contentType);
|
|
949
|
+
if (model.kind === "singleType") {
|
|
950
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
951
|
+
if (!document) {
|
|
952
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
953
|
+
}
|
|
954
|
+
action.entryDocumentId = document.documentId;
|
|
955
|
+
}
|
|
956
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
957
|
+
if (!release2) {
|
|
958
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
959
|
+
}
|
|
960
|
+
if (release2.releasedAt) {
|
|
961
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
962
|
+
}
|
|
963
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
964
|
+
{
|
|
965
|
+
contentType: action.contentType,
|
|
966
|
+
documentId: action.entryDocumentId,
|
|
967
|
+
locale: action.locale
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
strapi: strapi2
|
|
971
|
+
}
|
|
972
|
+
) : true;
|
|
973
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
974
|
+
data: {
|
|
975
|
+
...action,
|
|
976
|
+
release: release2.id,
|
|
977
|
+
isEntryValid: actionStatus
|
|
978
|
+
},
|
|
979
|
+
populate: { release: { select: ["id"] } }
|
|
980
|
+
});
|
|
981
|
+
if (!disableUpdateReleaseStatus) {
|
|
982
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
983
|
+
}
|
|
984
|
+
return releaseAction2;
|
|
985
|
+
},
|
|
986
|
+
async findPage(releaseId, query) {
|
|
987
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
988
|
+
where: { id: releaseId },
|
|
989
|
+
select: ["id"]
|
|
990
|
+
});
|
|
991
|
+
if (!release2) {
|
|
992
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
993
|
+
}
|
|
994
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
995
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
996
|
+
...dbQuery,
|
|
997
|
+
where: {
|
|
998
|
+
release: releaseId
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
1002
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
1003
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1004
|
+
const entry = await getEntry(
|
|
1005
|
+
{
|
|
1006
|
+
contentType: action.contentType,
|
|
1007
|
+
documentId: action.entryDocumentId,
|
|
1008
|
+
locale: action.locale,
|
|
1009
|
+
populate,
|
|
1010
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
1011
|
+
},
|
|
1012
|
+
{ strapi: strapi2 }
|
|
1013
|
+
);
|
|
1014
|
+
return {
|
|
1015
|
+
...action,
|
|
1016
|
+
entry,
|
|
1017
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1018
|
+
};
|
|
1019
|
+
});
|
|
1020
|
+
return {
|
|
1021
|
+
results: actionsWithEntry,
|
|
1022
|
+
pagination
|
|
1023
|
+
};
|
|
1024
|
+
},
|
|
1025
|
+
async groupActions(actions, groupBy) {
|
|
1026
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1027
|
+
if (!acc.includes(action.contentType)) {
|
|
1028
|
+
acc.push(action.contentType);
|
|
1029
|
+
}
|
|
1030
|
+
return acc;
|
|
1031
|
+
}, []);
|
|
1032
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1033
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1034
|
+
const formattedData = actions.map((action) => {
|
|
1035
|
+
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1036
|
+
return {
|
|
1037
|
+
...action,
|
|
1038
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1039
|
+
contentType: {
|
|
1040
|
+
displayName,
|
|
1041
|
+
mainFieldValue: action.entry[mainField],
|
|
1042
|
+
uid: action.contentType
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
});
|
|
1046
|
+
const groupName = getGroupName(groupBy);
|
|
1047
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
1026
1048
|
},
|
|
1027
|
-
|
|
1028
|
-
const
|
|
1049
|
+
getContentTypeModelsFromActions(actions) {
|
|
1050
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1051
|
+
if (!acc.includes(action.contentType)) {
|
|
1052
|
+
acc.push(action.contentType);
|
|
1053
|
+
}
|
|
1054
|
+
return acc;
|
|
1055
|
+
}, []);
|
|
1056
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1057
|
+
(acc, contentTypeUid) => {
|
|
1058
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1059
|
+
return acc;
|
|
1060
|
+
},
|
|
1061
|
+
{}
|
|
1062
|
+
);
|
|
1063
|
+
return contentTypeModelsMap;
|
|
1064
|
+
},
|
|
1065
|
+
async countActions(query) {
|
|
1066
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1067
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1068
|
+
},
|
|
1069
|
+
async update(actionId, releaseId, update) {
|
|
1070
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1029
1071
|
where: {
|
|
1030
1072
|
id: actionId,
|
|
1031
1073
|
release: {
|
|
@@ -1034,17 +1076,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1034
1076
|
$null: true
|
|
1035
1077
|
}
|
|
1036
1078
|
}
|
|
1037
|
-
}
|
|
1038
|
-
data: update
|
|
1079
|
+
}
|
|
1039
1080
|
});
|
|
1040
|
-
if (!
|
|
1081
|
+
if (!action) {
|
|
1041
1082
|
throw new utils.errors.NotFoundError(
|
|
1042
1083
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1043
1084
|
);
|
|
1044
1085
|
}
|
|
1086
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1087
|
+
{
|
|
1088
|
+
contentType: action.contentType,
|
|
1089
|
+
documentId: action.entryDocumentId,
|
|
1090
|
+
locale: action.locale
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
strapi: strapi2
|
|
1094
|
+
}
|
|
1095
|
+
) : true;
|
|
1096
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1097
|
+
where: {
|
|
1098
|
+
id: actionId,
|
|
1099
|
+
release: {
|
|
1100
|
+
id: releaseId,
|
|
1101
|
+
releasedAt: {
|
|
1102
|
+
$null: true
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
data: {
|
|
1107
|
+
...update,
|
|
1108
|
+
isEntryValid: actionStatus
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1045
1112
|
return updatedAction;
|
|
1046
1113
|
},
|
|
1047
|
-
async
|
|
1114
|
+
async delete(actionId, releaseId) {
|
|
1048
1115
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1049
1116
|
where: {
|
|
1050
1117
|
id: actionId,
|
|
@@ -1061,51 +1128,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1061
1128
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1062
1129
|
);
|
|
1063
1130
|
}
|
|
1064
|
-
|
|
1131
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1065
1132
|
return deletedAction;
|
|
1066
|
-
},
|
|
1067
|
-
async updateReleaseStatus(releaseId) {
|
|
1068
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
1069
|
-
this.countActions({
|
|
1070
|
-
filters: {
|
|
1071
|
-
release: releaseId
|
|
1072
|
-
}
|
|
1073
|
-
}),
|
|
1074
|
-
this.countActions({
|
|
1075
|
-
filters: {
|
|
1076
|
-
release: releaseId,
|
|
1077
|
-
isEntryValid: false
|
|
1078
|
-
}
|
|
1079
|
-
})
|
|
1080
|
-
]);
|
|
1081
|
-
if (totalActions > 0) {
|
|
1082
|
-
if (invalidActions > 0) {
|
|
1083
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1084
|
-
where: {
|
|
1085
|
-
id: releaseId
|
|
1086
|
-
},
|
|
1087
|
-
data: {
|
|
1088
|
-
status: "blocked"
|
|
1089
|
-
}
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1093
|
-
where: {
|
|
1094
|
-
id: releaseId
|
|
1095
|
-
},
|
|
1096
|
-
data: {
|
|
1097
|
-
status: "ready"
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
|
-
}
|
|
1101
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1102
|
-
where: {
|
|
1103
|
-
id: releaseId
|
|
1104
|
-
},
|
|
1105
|
-
data: {
|
|
1106
|
-
status: "empty"
|
|
1107
|
-
}
|
|
1108
|
-
});
|
|
1109
1133
|
}
|
|
1110
1134
|
};
|
|
1111
1135
|
};
|
|
@@ -1117,37 +1141,43 @@ class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
|
1117
1141
|
}
|
|
1118
1142
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1119
1143
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1120
|
-
const release2 = await strapi2.
|
|
1121
|
-
|
|
1144
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1145
|
+
where: {
|
|
1146
|
+
id: releaseId
|
|
1147
|
+
},
|
|
1148
|
+
populate: {
|
|
1149
|
+
actions: true
|
|
1150
|
+
}
|
|
1122
1151
|
});
|
|
1123
1152
|
if (!release2) {
|
|
1124
1153
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1125
1154
|
}
|
|
1126
1155
|
const isEntryInRelease = release2.actions.some(
|
|
1127
|
-
(action) =>
|
|
1156
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1128
1157
|
);
|
|
1129
1158
|
if (isEntryInRelease) {
|
|
1130
1159
|
throw new AlreadyOnReleaseError(
|
|
1131
|
-
`Entry with
|
|
1160
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1132
1161
|
);
|
|
1133
1162
|
}
|
|
1134
1163
|
},
|
|
1135
|
-
|
|
1164
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1136
1165
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1137
1166
|
if (!contentType) {
|
|
1138
1167
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1139
1168
|
}
|
|
1140
|
-
if (!contentType
|
|
1169
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1141
1170
|
throw new utils.errors.ValidationError(
|
|
1142
1171
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1143
1172
|
);
|
|
1144
1173
|
}
|
|
1174
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1175
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1176
|
+
}
|
|
1145
1177
|
},
|
|
1146
1178
|
async validatePendingReleasesLimit() {
|
|
1147
|
-
const
|
|
1148
|
-
|
|
1149
|
-
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1150
|
-
);
|
|
1179
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1180
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1151
1181
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1152
1182
|
filters: {
|
|
1153
1183
|
releasedAt: {
|
|
@@ -1160,8 +1190,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1160
1190
|
}
|
|
1161
1191
|
},
|
|
1162
1192
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1163
|
-
const pendingReleases = await strapi2.
|
|
1164
|
-
|
|
1193
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1194
|
+
where: {
|
|
1165
1195
|
releasedAt: {
|
|
1166
1196
|
$null: true
|
|
1167
1197
|
},
|
|
@@ -1190,7 +1220,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1190
1220
|
}
|
|
1191
1221
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1192
1222
|
try {
|
|
1193
|
-
await getService("release").publish(releaseId);
|
|
1223
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1194
1224
|
} catch (error) {
|
|
1195
1225
|
}
|
|
1196
1226
|
this.cancel(releaseId);
|
|
@@ -1232,85 +1262,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1232
1262
|
}
|
|
1233
1263
|
};
|
|
1234
1264
|
};
|
|
1265
|
+
const DEFAULT_SETTINGS = {
|
|
1266
|
+
defaultTimezone: null
|
|
1267
|
+
};
|
|
1268
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1269
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1270
|
+
return {
|
|
1271
|
+
async update({ settings: settings2 }) {
|
|
1272
|
+
const store = await getStore();
|
|
1273
|
+
store.set({ key: "settings", value: settings2 });
|
|
1274
|
+
return settings2;
|
|
1275
|
+
},
|
|
1276
|
+
async find() {
|
|
1277
|
+
const store = await getStore();
|
|
1278
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1279
|
+
return {
|
|
1280
|
+
...DEFAULT_SETTINGS,
|
|
1281
|
+
...settings2 || {}
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
};
|
|
1235
1286
|
const services = {
|
|
1236
1287
|
release: createReleaseService,
|
|
1288
|
+
"release-action": createReleaseActionService,
|
|
1237
1289
|
"release-validation": createReleaseValidationService,
|
|
1238
|
-
scheduling: createSchedulingService
|
|
1290
|
+
scheduling: createSchedulingService,
|
|
1291
|
+
settings: createSettingsService
|
|
1239
1292
|
};
|
|
1240
|
-
const RELEASE_SCHEMA =
|
|
1241
|
-
name:
|
|
1242
|
-
scheduledAt:
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
otherwise: yup__namespace.string().nullable()
|
|
1248
|
-
}),
|
|
1249
|
-
timezone: yup__namespace.string().when("isScheduled", {
|
|
1250
|
-
is: true,
|
|
1251
|
-
then: yup__namespace.string().required().nullable(),
|
|
1252
|
-
otherwise: yup__namespace.string().nullable()
|
|
1253
|
-
}),
|
|
1254
|
-
date: yup__namespace.string().when("isScheduled", {
|
|
1255
|
-
is: true,
|
|
1256
|
-
then: yup__namespace.string().required().nullable(),
|
|
1257
|
-
otherwise: yup__namespace.string().nullable()
|
|
1293
|
+
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1294
|
+
name: utils.yup.string().trim().required(),
|
|
1295
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1296
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1297
|
+
is: (value) => value !== null && value !== void 0,
|
|
1298
|
+
then: utils.yup.string().required(),
|
|
1299
|
+
otherwise: utils.yup.string().nullable()
|
|
1258
1300
|
})
|
|
1259
1301
|
}).required().noUnknown();
|
|
1302
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1303
|
+
contentType: utils.yup.string().required(),
|
|
1304
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1305
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1306
|
+
locale: utils.yup.string().nullable()
|
|
1307
|
+
}).required().noUnknown();
|
|
1260
1308
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1309
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1310
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1311
|
+
);
|
|
1261
1312
|
const releaseController = {
|
|
1262
|
-
|
|
1263
|
-
|
|
1313
|
+
/**
|
|
1314
|
+
* Find releases based on documents attached or not to the release.
|
|
1315
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1316
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1317
|
+
*/
|
|
1318
|
+
async findByDocumentAttached(ctx) {
|
|
1319
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1264
1320
|
ability: ctx.state.userAbility,
|
|
1265
1321
|
model: RELEASE_MODEL_UID
|
|
1266
1322
|
});
|
|
1267
1323
|
await permissionsManager.validateQuery(ctx.query);
|
|
1268
1324
|
const releaseService = getService("release", { strapi });
|
|
1269
|
-
const
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1325
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1326
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1327
|
+
const model = strapi.getModel(query.contentType);
|
|
1328
|
+
if (model.kind && model.kind === "singleType") {
|
|
1329
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1330
|
+
if (!document) {
|
|
1331
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1332
|
+
}
|
|
1333
|
+
query.entryDocumentId = document.documentId;
|
|
1334
|
+
}
|
|
1335
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1336
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1337
|
+
if (isEntryAttached) {
|
|
1338
|
+
const releases = await releaseService.findMany({
|
|
1339
|
+
where: {
|
|
1340
|
+
releasedAt: null,
|
|
1341
|
+
actions: {
|
|
1342
|
+
contentType,
|
|
1343
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1344
|
+
locale: locale ?? null
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
populate: {
|
|
1284
1348
|
actions: {
|
|
1285
|
-
|
|
1286
|
-
|
|
1349
|
+
fields: ["type"],
|
|
1350
|
+
filters: {
|
|
1351
|
+
contentType,
|
|
1352
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1353
|
+
locale: locale ?? null
|
|
1287
1354
|
}
|
|
1288
1355
|
}
|
|
1289
|
-
}
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
ctx.body = { data: releases };
|
|
1359
|
+
} else {
|
|
1360
|
+
const relatedReleases = await releaseService.findMany({
|
|
1361
|
+
where: {
|
|
1362
|
+
releasedAt: null,
|
|
1363
|
+
actions: {
|
|
1364
|
+
contentType,
|
|
1365
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1366
|
+
locale: locale ?? null
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1290
1369
|
});
|
|
1291
|
-
const
|
|
1370
|
+
const releases = await releaseService.findMany({
|
|
1292
1371
|
where: {
|
|
1372
|
+
$or: [
|
|
1373
|
+
{
|
|
1374
|
+
id: {
|
|
1375
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1376
|
+
}
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
actions: null
|
|
1380
|
+
}
|
|
1381
|
+
],
|
|
1293
1382
|
releasedAt: null
|
|
1294
1383
|
}
|
|
1295
1384
|
});
|
|
1296
|
-
ctx.body = { data
|
|
1385
|
+
ctx.body = { data: releases };
|
|
1297
1386
|
}
|
|
1298
1387
|
},
|
|
1388
|
+
async findPage(ctx) {
|
|
1389
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1390
|
+
ability: ctx.state.userAbility,
|
|
1391
|
+
model: RELEASE_MODEL_UID
|
|
1392
|
+
});
|
|
1393
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1394
|
+
const releaseService = getService("release", { strapi });
|
|
1395
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1396
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1397
|
+
const data = results.map((release2) => {
|
|
1398
|
+
const { actions, ...releaseData } = release2;
|
|
1399
|
+
return {
|
|
1400
|
+
...releaseData,
|
|
1401
|
+
actions: {
|
|
1402
|
+
meta: {
|
|
1403
|
+
count: actions.count
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
});
|
|
1408
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1409
|
+
where: {
|
|
1410
|
+
releasedAt: null
|
|
1411
|
+
}
|
|
1412
|
+
});
|
|
1413
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1414
|
+
},
|
|
1299
1415
|
async findOne(ctx) {
|
|
1300
1416
|
const id = ctx.params.id;
|
|
1301
1417
|
const releaseService = getService("release", { strapi });
|
|
1418
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1302
1419
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1303
1420
|
if (!release2) {
|
|
1304
1421
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1305
1422
|
}
|
|
1306
|
-
const count = await
|
|
1423
|
+
const count = await releaseActionService.countActions({
|
|
1307
1424
|
filters: {
|
|
1308
1425
|
release: id
|
|
1309
1426
|
}
|
|
1310
1427
|
});
|
|
1311
1428
|
const sanitizedRelease = {
|
|
1312
1429
|
...release2,
|
|
1313
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1430
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1314
1431
|
};
|
|
1315
1432
|
const data = {
|
|
1316
1433
|
...sanitizedRelease,
|
|
@@ -1322,19 +1439,63 @@ const releaseController = {
|
|
|
1322
1439
|
};
|
|
1323
1440
|
ctx.body = { data };
|
|
1324
1441
|
},
|
|
1442
|
+
async mapEntriesToReleases(ctx) {
|
|
1443
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1444
|
+
if (!contentTypeUid || !documentIds) {
|
|
1445
|
+
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1446
|
+
}
|
|
1447
|
+
const releaseService = getService("release", { strapi });
|
|
1448
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1449
|
+
where: {
|
|
1450
|
+
releasedAt: null,
|
|
1451
|
+
actions: {
|
|
1452
|
+
contentType: contentTypeUid,
|
|
1453
|
+
entryDocumentId: {
|
|
1454
|
+
$in: documentIds
|
|
1455
|
+
},
|
|
1456
|
+
locale
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
populate: {
|
|
1460
|
+
actions: true
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1464
|
+
(acc, release2) => {
|
|
1465
|
+
release2.actions.forEach((action) => {
|
|
1466
|
+
if (action.contentType !== contentTypeUid) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (locale && action.locale !== locale) {
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
if (!acc[action.entryDocumentId]) {
|
|
1473
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1474
|
+
} else {
|
|
1475
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
return acc;
|
|
1479
|
+
},
|
|
1480
|
+
{}
|
|
1481
|
+
);
|
|
1482
|
+
ctx.body = {
|
|
1483
|
+
data: mappedEntriesInReleases
|
|
1484
|
+
};
|
|
1485
|
+
},
|
|
1325
1486
|
async create(ctx) {
|
|
1326
1487
|
const user = ctx.state.user;
|
|
1327
1488
|
const releaseArgs = ctx.request.body;
|
|
1328
1489
|
await validateRelease(releaseArgs);
|
|
1329
1490
|
const releaseService = getService("release", { strapi });
|
|
1330
1491
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1331
|
-
const permissionsManager = strapi.admin
|
|
1492
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1332
1493
|
ability: ctx.state.userAbility,
|
|
1333
1494
|
model: RELEASE_MODEL_UID
|
|
1334
1495
|
});
|
|
1335
|
-
ctx.
|
|
1496
|
+
ctx.created({
|
|
1336
1497
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1337
|
-
};
|
|
1498
|
+
});
|
|
1338
1499
|
},
|
|
1339
1500
|
async update(ctx) {
|
|
1340
1501
|
const user = ctx.state.user;
|
|
@@ -1343,7 +1504,7 @@ const releaseController = {
|
|
|
1343
1504
|
await validateRelease(releaseArgs);
|
|
1344
1505
|
const releaseService = getService("release", { strapi });
|
|
1345
1506
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1346
|
-
const permissionsManager = strapi.admin
|
|
1507
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1347
1508
|
ability: ctx.state.userAbility,
|
|
1348
1509
|
model: RELEASE_MODEL_UID
|
|
1349
1510
|
});
|
|
@@ -1360,18 +1521,18 @@ const releaseController = {
|
|
|
1360
1521
|
};
|
|
1361
1522
|
},
|
|
1362
1523
|
async publish(ctx) {
|
|
1363
|
-
const user = ctx.state.user;
|
|
1364
1524
|
const id = ctx.params.id;
|
|
1365
1525
|
const releaseService = getService("release", { strapi });
|
|
1366
|
-
const
|
|
1526
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1527
|
+
const release2 = await releaseService.publish(id);
|
|
1367
1528
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1368
|
-
|
|
1529
|
+
releaseActionService.countActions({
|
|
1369
1530
|
filters: {
|
|
1370
1531
|
release: id,
|
|
1371
1532
|
type: "publish"
|
|
1372
1533
|
}
|
|
1373
1534
|
}),
|
|
1374
|
-
|
|
1535
|
+
releaseActionService.countActions({
|
|
1375
1536
|
filters: {
|
|
1376
1537
|
release: id,
|
|
1377
1538
|
type: "unpublish"
|
|
@@ -1389,27 +1550,30 @@ const releaseController = {
|
|
|
1389
1550
|
}
|
|
1390
1551
|
};
|
|
1391
1552
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
}).required(),
|
|
1553
|
+
contentType: utils.yup.string().required(),
|
|
1554
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1555
|
+
locale: utils.yup.string(),
|
|
1396
1556
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1397
1557
|
});
|
|
1398
1558
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1399
1559
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1400
1560
|
});
|
|
1561
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1562
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1563
|
+
});
|
|
1401
1564
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1402
1565
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1566
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1403
1567
|
const releaseActionController = {
|
|
1404
1568
|
async create(ctx) {
|
|
1405
1569
|
const releaseId = ctx.params.releaseId;
|
|
1406
1570
|
const releaseActionArgs = ctx.request.body;
|
|
1407
1571
|
await validateReleaseAction(releaseActionArgs);
|
|
1408
|
-
const
|
|
1409
|
-
const releaseAction2 = await
|
|
1410
|
-
ctx.
|
|
1572
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1573
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1574
|
+
ctx.created({
|
|
1411
1575
|
data: releaseAction2
|
|
1412
|
-
};
|
|
1576
|
+
});
|
|
1413
1577
|
},
|
|
1414
1578
|
async createMany(ctx) {
|
|
1415
1579
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1417,12 +1581,15 @@ const releaseActionController = {
|
|
|
1417
1581
|
await Promise.all(
|
|
1418
1582
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1419
1583
|
);
|
|
1584
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1420
1585
|
const releaseService = getService("release", { strapi });
|
|
1421
1586
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1422
1587
|
const releaseActions2 = await Promise.all(
|
|
1423
1588
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1424
1589
|
try {
|
|
1425
|
-
const action = await
|
|
1590
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1591
|
+
disableUpdateReleaseStatus: true
|
|
1592
|
+
});
|
|
1426
1593
|
return action;
|
|
1427
1594
|
} catch (error) {
|
|
1428
1595
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1435,43 +1602,54 @@ const releaseActionController = {
|
|
|
1435
1602
|
return releaseActions2;
|
|
1436
1603
|
});
|
|
1437
1604
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1438
|
-
|
|
1605
|
+
if (newReleaseActions.length > 0) {
|
|
1606
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1607
|
+
}
|
|
1608
|
+
ctx.created({
|
|
1439
1609
|
data: newReleaseActions,
|
|
1440
1610
|
meta: {
|
|
1441
1611
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1442
1612
|
totalEntries: releaseActions.length
|
|
1443
1613
|
}
|
|
1444
|
-
};
|
|
1614
|
+
});
|
|
1445
1615
|
},
|
|
1446
1616
|
async findMany(ctx) {
|
|
1447
1617
|
const releaseId = ctx.params.releaseId;
|
|
1448
|
-
const permissionsManager = strapi.admin
|
|
1618
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1449
1619
|
ability: ctx.state.userAbility,
|
|
1450
1620
|
model: RELEASE_ACTION_MODEL_UID
|
|
1451
1621
|
});
|
|
1622
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1623
|
+
if (ctx.query.groupBy) {
|
|
1624
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1625
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1629
|
+
delete ctx.query.groupBy;
|
|
1452
1630
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1453
|
-
const
|
|
1454
|
-
const { results, pagination } = await
|
|
1455
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1631
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1632
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1456
1633
|
...query
|
|
1457
1634
|
});
|
|
1458
1635
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1459
1636
|
if (acc[action.contentType]) {
|
|
1460
1637
|
return acc;
|
|
1461
1638
|
}
|
|
1462
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1639
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1463
1640
|
ability: ctx.state.userAbility,
|
|
1464
1641
|
model: action.contentType
|
|
1465
1642
|
});
|
|
1466
1643
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1467
1644
|
return acc;
|
|
1468
1645
|
}, {});
|
|
1469
|
-
const sanitizedResults = await utils.
|
|
1646
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1470
1647
|
...action,
|
|
1471
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1648
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1472
1649
|
}));
|
|
1473
|
-
const groupedData = await
|
|
1474
|
-
const contentTypes2 =
|
|
1650
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1651
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1652
|
+
const releaseService = getService("release", { strapi });
|
|
1475
1653
|
const components = await releaseService.getAllComponents();
|
|
1476
1654
|
ctx.body = {
|
|
1477
1655
|
data: groupedData,
|
|
@@ -1487,8 +1665,8 @@ const releaseActionController = {
|
|
|
1487
1665
|
const releaseId = ctx.params.releaseId;
|
|
1488
1666
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1489
1667
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1490
|
-
const
|
|
1491
|
-
const updatedAction = await
|
|
1668
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1669
|
+
const updatedAction = await releaseActionService.update(
|
|
1492
1670
|
actionId,
|
|
1493
1671
|
releaseId,
|
|
1494
1672
|
releaseActionUpdateArgs
|
|
@@ -1500,17 +1678,71 @@ const releaseActionController = {
|
|
|
1500
1678
|
async delete(ctx) {
|
|
1501
1679
|
const actionId = ctx.params.actionId;
|
|
1502
1680
|
const releaseId = ctx.params.releaseId;
|
|
1503
|
-
const
|
|
1504
|
-
const deletedReleaseAction = await
|
|
1681
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1682
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1505
1683
|
ctx.body = {
|
|
1506
1684
|
data: deletedReleaseAction
|
|
1507
1685
|
};
|
|
1508
1686
|
}
|
|
1509
1687
|
};
|
|
1510
|
-
const
|
|
1688
|
+
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1689
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1690
|
+
}).required().noUnknown();
|
|
1691
|
+
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1692
|
+
const settingsController = {
|
|
1693
|
+
async find(ctx) {
|
|
1694
|
+
const settingsService = getService("settings", { strapi });
|
|
1695
|
+
const settings2 = await settingsService.find();
|
|
1696
|
+
ctx.body = { data: settings2 };
|
|
1697
|
+
},
|
|
1698
|
+
async update(ctx) {
|
|
1699
|
+
const settingsBody = ctx.request.body;
|
|
1700
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1701
|
+
const settingsService = getService("settings", { strapi });
|
|
1702
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1703
|
+
ctx.body = { data: updatedSettings };
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
const controllers = {
|
|
1707
|
+
release: releaseController,
|
|
1708
|
+
"release-action": releaseActionController,
|
|
1709
|
+
settings: settingsController
|
|
1710
|
+
};
|
|
1511
1711
|
const release = {
|
|
1512
1712
|
type: "admin",
|
|
1513
1713
|
routes: [
|
|
1714
|
+
{
|
|
1715
|
+
method: "GET",
|
|
1716
|
+
path: "/mapEntriesToReleases",
|
|
1717
|
+
handler: "release.mapEntriesToReleases",
|
|
1718
|
+
config: {
|
|
1719
|
+
policies: [
|
|
1720
|
+
"admin::isAuthenticatedAdmin",
|
|
1721
|
+
{
|
|
1722
|
+
name: "admin::hasPermissions",
|
|
1723
|
+
config: {
|
|
1724
|
+
actions: ["plugin::content-releases.read"]
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
]
|
|
1728
|
+
}
|
|
1729
|
+
},
|
|
1730
|
+
{
|
|
1731
|
+
method: "GET",
|
|
1732
|
+
path: "/getByDocumentAttached",
|
|
1733
|
+
handler: "release.findByDocumentAttached",
|
|
1734
|
+
config: {
|
|
1735
|
+
policies: [
|
|
1736
|
+
"admin::isAuthenticatedAdmin",
|
|
1737
|
+
{
|
|
1738
|
+
name: "admin::hasPermissions",
|
|
1739
|
+
config: {
|
|
1740
|
+
actions: ["plugin::content-releases.read"]
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
]
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1514
1746
|
{
|
|
1515
1747
|
method: "POST",
|
|
1516
1748
|
path: "/",
|
|
@@ -1530,7 +1762,7 @@ const release = {
|
|
|
1530
1762
|
{
|
|
1531
1763
|
method: "GET",
|
|
1532
1764
|
path: "/",
|
|
1533
|
-
handler: "release.
|
|
1765
|
+
handler: "release.findPage",
|
|
1534
1766
|
config: {
|
|
1535
1767
|
policies: [
|
|
1536
1768
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1694,13 +1926,50 @@ const releaseAction = {
|
|
|
1694
1926
|
}
|
|
1695
1927
|
]
|
|
1696
1928
|
};
|
|
1929
|
+
const settings = {
|
|
1930
|
+
type: "admin",
|
|
1931
|
+
routes: [
|
|
1932
|
+
{
|
|
1933
|
+
method: "GET",
|
|
1934
|
+
path: "/settings",
|
|
1935
|
+
handler: "settings.find",
|
|
1936
|
+
config: {
|
|
1937
|
+
policies: [
|
|
1938
|
+
"admin::isAuthenticatedAdmin",
|
|
1939
|
+
{
|
|
1940
|
+
name: "admin::hasPermissions",
|
|
1941
|
+
config: {
|
|
1942
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
]
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
{
|
|
1949
|
+
method: "PUT",
|
|
1950
|
+
path: "/settings",
|
|
1951
|
+
handler: "settings.update",
|
|
1952
|
+
config: {
|
|
1953
|
+
policies: [
|
|
1954
|
+
"admin::isAuthenticatedAdmin",
|
|
1955
|
+
{
|
|
1956
|
+
name: "admin::hasPermissions",
|
|
1957
|
+
config: {
|
|
1958
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
]
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
]
|
|
1965
|
+
};
|
|
1697
1966
|
const routes = {
|
|
1967
|
+
settings,
|
|
1698
1968
|
release,
|
|
1699
1969
|
"release-action": releaseAction
|
|
1700
1970
|
};
|
|
1701
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1702
1971
|
const getPlugin = () => {
|
|
1703
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1972
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1704
1973
|
return {
|
|
1705
1974
|
register,
|
|
1706
1975
|
bootstrap,
|