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