@strapi/content-releases 0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8 → 0.0.0-experimental.f28dba7c374eae9c02b95b4b77aba4c3ad41a841
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-JwN_xBnA.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 +646 -809
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +646 -810
- package/dist/server/index.mjs.map +1 -1
- package/package.json +37 -31
- package/dist/_chunks/App-BFo3ibui.js +0 -1395
- package/dist/_chunks/App-BFo3ibui.js.map +0 -1
- package/dist/_chunks/App-JwN_xBnA.mjs.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-BanjZwEc.js +0 -178
- package/dist/_chunks/ReleasesSettingsPage-BanjZwEc.js.map +0 -1
- package/dist/_chunks/ReleasesSettingsPage-CNMXGcZC.mjs +0 -178
- package/dist/_chunks/ReleasesSettingsPage-CNMXGcZC.mjs.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-C_e6DQb0.mjs +0 -1342
- package/dist/_chunks/index-C_e6DQb0.mjs.map +0 -1
- package/dist/_chunks/index-Em3KctMx.js +0 -1361
- package/dist/_chunks/index-Em3KctMx.js.map +0 -1
- package/dist/_chunks/schemas-63pFihNF.mjs +0 -44
- package/dist/_chunks/schemas-63pFihNF.mjs.map +0 -1
- package/dist/_chunks/schemas-z5zp-_Gd.js +0 -62
- package/dist/_chunks/schemas-z5zp-_Gd.js.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 -2113
- 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 -1826
- package/dist/server/src/services/index.d.ts.map +0 -1
- package/dist/server/src/services/release-action.d.ts +0 -36
- 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
|
|
@@ -836,220 +1036,17 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
836
1036
|
}).transacting(trx).execute();
|
|
837
1037
|
return {
|
|
838
1038
|
release: null,
|
|
839
|
-
error: error2
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
});
|
|
843
|
-
if (error instanceof 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) {
|
|
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 release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
941
|
-
if (!release2) {
|
|
942
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
943
|
-
}
|
|
944
|
-
if (release2.releasedAt) {
|
|
945
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
946
|
-
}
|
|
947
|
-
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
948
|
-
{
|
|
949
|
-
contentType: action.contentType,
|
|
950
|
-
documentId: action.entryDocumentId,
|
|
951
|
-
locale: action.locale
|
|
952
|
-
},
|
|
953
|
-
{
|
|
954
|
-
strapi: strapi2
|
|
1039
|
+
error: error2
|
|
1040
|
+
};
|
|
955
1041
|
}
|
|
956
|
-
) : true;
|
|
957
|
-
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
958
|
-
data: {
|
|
959
|
-
...action,
|
|
960
|
-
release: release2.id,
|
|
961
|
-
isEntryValid: actionStatus
|
|
962
|
-
},
|
|
963
|
-
populate: { release: { select: ["id"] } }
|
|
964
|
-
});
|
|
965
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
966
|
-
return releaseAction2;
|
|
967
|
-
},
|
|
968
|
-
async findPage(releaseId, query) {
|
|
969
|
-
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
970
|
-
where: { id: releaseId },
|
|
971
|
-
select: ["id"]
|
|
972
1042
|
});
|
|
973
|
-
if (
|
|
974
|
-
throw
|
|
1043
|
+
if (error) {
|
|
1044
|
+
throw error;
|
|
975
1045
|
}
|
|
976
|
-
|
|
977
|
-
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
978
|
-
...dbQuery,
|
|
979
|
-
where: {
|
|
980
|
-
release: releaseId
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
984
|
-
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
985
|
-
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
986
|
-
const entry = await getEntry(
|
|
987
|
-
{
|
|
988
|
-
contentType: action.contentType,
|
|
989
|
-
documentId: action.entryDocumentId,
|
|
990
|
-
locale: action.locale,
|
|
991
|
-
populate,
|
|
992
|
-
status: action.type === "publish" ? "draft" : "published"
|
|
993
|
-
},
|
|
994
|
-
{ strapi: strapi2 }
|
|
995
|
-
);
|
|
996
|
-
return {
|
|
997
|
-
...action,
|
|
998
|
-
entry,
|
|
999
|
-
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1000
|
-
};
|
|
1001
|
-
});
|
|
1002
|
-
return {
|
|
1003
|
-
results: actionsWithEntry,
|
|
1004
|
-
pagination
|
|
1005
|
-
};
|
|
1006
|
-
},
|
|
1007
|
-
async groupActions(actions, groupBy) {
|
|
1008
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1009
|
-
if (!acc.includes(action.contentType)) {
|
|
1010
|
-
acc.push(action.contentType);
|
|
1011
|
-
}
|
|
1012
|
-
return acc;
|
|
1013
|
-
}, []);
|
|
1014
|
-
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1015
|
-
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1016
|
-
const formattedData = actions.map((action) => {
|
|
1017
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1018
|
-
return {
|
|
1019
|
-
...action,
|
|
1020
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1021
|
-
contentType: {
|
|
1022
|
-
displayName,
|
|
1023
|
-
mainFieldValue: action.entry[mainField],
|
|
1024
|
-
uid: action.contentType
|
|
1025
|
-
}
|
|
1026
|
-
};
|
|
1027
|
-
});
|
|
1028
|
-
const groupName = getGroupName(groupBy);
|
|
1029
|
-
return ___default.default.groupBy(groupName)(formattedData);
|
|
1030
|
-
},
|
|
1031
|
-
getContentTypeModelsFromActions(actions) {
|
|
1032
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1033
|
-
if (!acc.includes(action.contentType)) {
|
|
1034
|
-
acc.push(action.contentType);
|
|
1035
|
-
}
|
|
1036
|
-
return acc;
|
|
1037
|
-
}, []);
|
|
1038
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1039
|
-
(acc, contentTypeUid) => {
|
|
1040
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1041
|
-
return acc;
|
|
1042
|
-
},
|
|
1043
|
-
{}
|
|
1044
|
-
);
|
|
1045
|
-
return contentTypeModelsMap;
|
|
1046
|
-
},
|
|
1047
|
-
async countActions(query) {
|
|
1048
|
-
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1049
|
-
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1046
|
+
return release2;
|
|
1050
1047
|
},
|
|
1051
|
-
async
|
|
1052
|
-
const
|
|
1048
|
+
async updateAction(actionId, releaseId, update) {
|
|
1049
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1053
1050
|
where: {
|
|
1054
1051
|
id: actionId,
|
|
1055
1052
|
release: {
|
|
@@ -1058,42 +1055,17 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
|
1058
1055
|
$null: true
|
|
1059
1056
|
}
|
|
1060
1057
|
}
|
|
1061
|
-
}
|
|
1058
|
+
},
|
|
1059
|
+
data: update
|
|
1062
1060
|
});
|
|
1063
|
-
if (!
|
|
1061
|
+
if (!updatedAction) {
|
|
1064
1062
|
throw new utils.errors.NotFoundError(
|
|
1065
1063
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1066
1064
|
);
|
|
1067
1065
|
}
|
|
1068
|
-
const actionStatus = update.type === "publish" ? getDraftEntryValidStatus(
|
|
1069
|
-
{
|
|
1070
|
-
contentType: action.contentType,
|
|
1071
|
-
documentId: action.entryDocumentId,
|
|
1072
|
-
locale: action.locale
|
|
1073
|
-
},
|
|
1074
|
-
{
|
|
1075
|
-
strapi: strapi2
|
|
1076
|
-
}
|
|
1077
|
-
) : true;
|
|
1078
|
-
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1079
|
-
where: {
|
|
1080
|
-
id: actionId,
|
|
1081
|
-
release: {
|
|
1082
|
-
id: releaseId,
|
|
1083
|
-
releasedAt: {
|
|
1084
|
-
$null: true
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
},
|
|
1088
|
-
data: {
|
|
1089
|
-
...update,
|
|
1090
|
-
isEntryValid: actionStatus
|
|
1091
|
-
}
|
|
1092
|
-
});
|
|
1093
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1094
1066
|
return updatedAction;
|
|
1095
1067
|
},
|
|
1096
|
-
async
|
|
1068
|
+
async deleteAction(actionId, releaseId) {
|
|
1097
1069
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1098
1070
|
where: {
|
|
1099
1071
|
id: actionId,
|
|
@@ -1110,8 +1082,51 @@ const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
|
1110
1082
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1111
1083
|
);
|
|
1112
1084
|
}
|
|
1113
|
-
|
|
1085
|
+
this.updateReleaseStatus(releaseId);
|
|
1114
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
|
+
});
|
|
1115
1130
|
}
|
|
1116
1131
|
};
|
|
1117
1132
|
};
|
|
@@ -1123,43 +1138,37 @@ class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
|
1123
1138
|
}
|
|
1124
1139
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1125
1140
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1126
|
-
const release2 = await strapi2.
|
|
1127
|
-
|
|
1128
|
-
id: releaseId
|
|
1129
|
-
},
|
|
1130
|
-
populate: {
|
|
1131
|
-
actions: true
|
|
1132
|
-
}
|
|
1141
|
+
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
1142
|
+
populate: { actions: { populate: { entry: { fields: ["id"] } } } }
|
|
1133
1143
|
});
|
|
1134
1144
|
if (!release2) {
|
|
1135
1145
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1136
1146
|
}
|
|
1137
1147
|
const isEntryInRelease = release2.actions.some(
|
|
1138
|
-
(action) => action.
|
|
1148
|
+
(action) => Number(action.entry.id) === Number(releaseActionArgs.entry.id) && action.contentType === releaseActionArgs.entry.contentType
|
|
1139
1149
|
);
|
|
1140
1150
|
if (isEntryInRelease) {
|
|
1141
1151
|
throw new AlreadyOnReleaseError(
|
|
1142
|
-
`Entry with
|
|
1152
|
+
`Entry with id ${releaseActionArgs.entry.id} and contentType ${releaseActionArgs.entry.contentType} already exists in release with id ${releaseId}`
|
|
1143
1153
|
);
|
|
1144
1154
|
}
|
|
1145
1155
|
},
|
|
1146
|
-
|
|
1156
|
+
validateEntryContentType(contentTypeUid) {
|
|
1147
1157
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1148
1158
|
if (!contentType) {
|
|
1149
1159
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1150
1160
|
}
|
|
1151
|
-
if (!
|
|
1161
|
+
if (!contentType.options?.draftAndPublish) {
|
|
1152
1162
|
throw new utils.errors.ValidationError(
|
|
1153
1163
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1154
1164
|
);
|
|
1155
1165
|
}
|
|
1156
|
-
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1157
|
-
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1158
|
-
}
|
|
1159
1166
|
},
|
|
1160
1167
|
async validatePendingReleasesLimit() {
|
|
1161
|
-
const
|
|
1162
|
-
|
|
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
|
+
);
|
|
1163
1172
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1164
1173
|
filters: {
|
|
1165
1174
|
releasedAt: {
|
|
@@ -1172,8 +1181,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1172
1181
|
}
|
|
1173
1182
|
},
|
|
1174
1183
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1175
|
-
const pendingReleases = await strapi2.
|
|
1176
|
-
|
|
1184
|
+
const pendingReleases = await strapi2.entityService.findMany(RELEASE_MODEL_UID, {
|
|
1185
|
+
filters: {
|
|
1177
1186
|
releasedAt: {
|
|
1178
1187
|
$null: true
|
|
1179
1188
|
},
|
|
@@ -1202,7 +1211,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1202
1211
|
}
|
|
1203
1212
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1204
1213
|
try {
|
|
1205
|
-
await getService("release"
|
|
1214
|
+
await getService("release").publish(releaseId);
|
|
1206
1215
|
} catch (error) {
|
|
1207
1216
|
}
|
|
1208
1217
|
this.cancel(releaseId);
|
|
@@ -1244,159 +1253,85 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1244
1253
|
}
|
|
1245
1254
|
};
|
|
1246
1255
|
};
|
|
1247
|
-
const DEFAULT_SETTINGS = {
|
|
1248
|
-
defaultTimezone: null
|
|
1249
|
-
};
|
|
1250
|
-
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1251
|
-
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1252
|
-
return {
|
|
1253
|
-
async update({ settings: settings2 }) {
|
|
1254
|
-
const store = await getStore();
|
|
1255
|
-
store.set({ key: "settings", value: settings2 });
|
|
1256
|
-
return settings2;
|
|
1257
|
-
},
|
|
1258
|
-
async find() {
|
|
1259
|
-
const store = await getStore();
|
|
1260
|
-
const settings2 = await store.get({ key: "settings" });
|
|
1261
|
-
return {
|
|
1262
|
-
...DEFAULT_SETTINGS,
|
|
1263
|
-
...settings2 || {}
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
};
|
|
1267
|
-
};
|
|
1268
1256
|
const services = {
|
|
1269
1257
|
release: createReleaseService,
|
|
1270
|
-
"release-action": createReleaseActionService,
|
|
1271
1258
|
"release-validation": createReleaseValidationService,
|
|
1272
|
-
scheduling: createSchedulingService
|
|
1273
|
-
settings: createSettingsService
|
|
1259
|
+
scheduling: createSchedulingService
|
|
1274
1260
|
};
|
|
1275
|
-
const RELEASE_SCHEMA =
|
|
1276
|
-
name:
|
|
1277
|
-
scheduledAt:
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
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()
|
|
1282
1279
|
})
|
|
1283
1280
|
}).required().noUnknown();
|
|
1284
|
-
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1285
|
-
contentType: utils.yup.string().required(),
|
|
1286
|
-
entryDocumentId: utils.yup.string().nullable(),
|
|
1287
|
-
hasEntryAttached: utils.yup.string().nullable(),
|
|
1288
|
-
locale: utils.yup.string().nullable()
|
|
1289
|
-
}).required().noUnknown();
|
|
1290
1281
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1291
|
-
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1292
|
-
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1293
|
-
);
|
|
1294
1282
|
const releaseController = {
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1298
|
-
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1299
|
-
*/
|
|
1300
|
-
async findByDocumentAttached(ctx) {
|
|
1301
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1283
|
+
async findMany(ctx) {
|
|
1284
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1302
1285
|
ability: ctx.state.userAbility,
|
|
1303
1286
|
model: RELEASE_MODEL_UID
|
|
1304
1287
|
});
|
|
1305
1288
|
await permissionsManager.validateQuery(ctx.query);
|
|
1306
1289
|
const releaseService = getService("release", { strapi });
|
|
1307
|
-
const
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
const
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
actions: {
|
|
1316
|
-
contentType,
|
|
1317
|
-
entryDocumentId: entryDocumentId ?? null,
|
|
1318
|
-
locale: locale ?? null
|
|
1319
|
-
}
|
|
1320
|
-
},
|
|
1321
|
-
populate: {
|
|
1322
|
-
actions: {
|
|
1323
|
-
fields: ["type"]
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
});
|
|
1327
|
-
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 };
|
|
1328
1298
|
} else {
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
|
|
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,
|
|
1332
1305
|
actions: {
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1306
|
+
meta: {
|
|
1307
|
+
count: actions.count
|
|
1308
|
+
}
|
|
1336
1309
|
}
|
|
1337
|
-
}
|
|
1310
|
+
};
|
|
1338
1311
|
});
|
|
1339
|
-
const
|
|
1312
|
+
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1340
1313
|
where: {
|
|
1341
|
-
$or: [
|
|
1342
|
-
{
|
|
1343
|
-
id: {
|
|
1344
|
-
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1345
|
-
}
|
|
1346
|
-
},
|
|
1347
|
-
{
|
|
1348
|
-
actions: null
|
|
1349
|
-
}
|
|
1350
|
-
],
|
|
1351
1314
|
releasedAt: null
|
|
1352
1315
|
}
|
|
1353
1316
|
});
|
|
1354
|
-
ctx.body = { data:
|
|
1317
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1355
1318
|
}
|
|
1356
1319
|
},
|
|
1357
|
-
async findPage(ctx) {
|
|
1358
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1359
|
-
ability: ctx.state.userAbility,
|
|
1360
|
-
model: RELEASE_MODEL_UID
|
|
1361
|
-
});
|
|
1362
|
-
await permissionsManager.validateQuery(ctx.query);
|
|
1363
|
-
const releaseService = getService("release", { strapi });
|
|
1364
|
-
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1365
|
-
const { results, pagination } = await releaseService.findPage(query);
|
|
1366
|
-
const data = results.map((release2) => {
|
|
1367
|
-
const { actions, ...releaseData } = release2;
|
|
1368
|
-
return {
|
|
1369
|
-
...releaseData,
|
|
1370
|
-
actions: {
|
|
1371
|
-
meta: {
|
|
1372
|
-
count: actions.count
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
};
|
|
1376
|
-
});
|
|
1377
|
-
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1378
|
-
where: {
|
|
1379
|
-
releasedAt: null
|
|
1380
|
-
}
|
|
1381
|
-
});
|
|
1382
|
-
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1383
|
-
},
|
|
1384
1320
|
async findOne(ctx) {
|
|
1385
1321
|
const id = ctx.params.id;
|
|
1386
1322
|
const releaseService = getService("release", { strapi });
|
|
1387
|
-
const releaseActionService = getService("release-action", { strapi });
|
|
1388
1323
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1389
1324
|
if (!release2) {
|
|
1390
1325
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1391
1326
|
}
|
|
1392
|
-
const count = await
|
|
1327
|
+
const count = await releaseService.countActions({
|
|
1393
1328
|
filters: {
|
|
1394
1329
|
release: id
|
|
1395
1330
|
}
|
|
1396
1331
|
});
|
|
1397
1332
|
const sanitizedRelease = {
|
|
1398
1333
|
...release2,
|
|
1399
|
-
createdBy: release2.createdBy ? strapi.
|
|
1334
|
+
createdBy: release2.createdBy ? strapi.admin.services.user.sanitizeUser(release2.createdBy) : null
|
|
1400
1335
|
};
|
|
1401
1336
|
const data = {
|
|
1402
1337
|
...sanitizedRelease,
|
|
@@ -1409,39 +1344,22 @@ const releaseController = {
|
|
|
1409
1344
|
ctx.body = { data };
|
|
1410
1345
|
},
|
|
1411
1346
|
async mapEntriesToReleases(ctx) {
|
|
1412
|
-
const { contentTypeUid,
|
|
1413
|
-
if (!contentTypeUid || !
|
|
1347
|
+
const { contentTypeUid, entriesIds } = ctx.query;
|
|
1348
|
+
if (!contentTypeUid || !entriesIds) {
|
|
1414
1349
|
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1415
1350
|
}
|
|
1416
1351
|
const releaseService = getService("release", { strapi });
|
|
1417
|
-
const releasesWithActions = await releaseService.
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
contentType: contentTypeUid,
|
|
1422
|
-
entryDocumentId: {
|
|
1423
|
-
$in: documentIds
|
|
1424
|
-
},
|
|
1425
|
-
locale
|
|
1426
|
-
}
|
|
1427
|
-
},
|
|
1428
|
-
populate: {
|
|
1429
|
-
actions: true
|
|
1430
|
-
}
|
|
1431
|
-
});
|
|
1352
|
+
const releasesWithActions = await releaseService.findManyWithContentTypeEntryAttached(
|
|
1353
|
+
contentTypeUid,
|
|
1354
|
+
entriesIds
|
|
1355
|
+
);
|
|
1432
1356
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1433
1357
|
(acc, release2) => {
|
|
1434
1358
|
release2.actions.forEach((action) => {
|
|
1435
|
-
if (action.
|
|
1436
|
-
|
|
1437
|
-
}
|
|
1438
|
-
if (locale && action.locale !== locale) {
|
|
1439
|
-
return;
|
|
1440
|
-
}
|
|
1441
|
-
if (!acc[action.entryDocumentId]) {
|
|
1442
|
-
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1359
|
+
if (!acc[action.entry.id]) {
|
|
1360
|
+
acc[action.entry.id] = [{ id: release2.id, name: release2.name }];
|
|
1443
1361
|
} else {
|
|
1444
|
-
acc[action.
|
|
1362
|
+
acc[action.entry.id].push({ id: release2.id, name: release2.name });
|
|
1445
1363
|
}
|
|
1446
1364
|
});
|
|
1447
1365
|
return acc;
|
|
@@ -1458,13 +1376,13 @@ const releaseController = {
|
|
|
1458
1376
|
await validateRelease(releaseArgs);
|
|
1459
1377
|
const releaseService = getService("release", { strapi });
|
|
1460
1378
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1461
|
-
const permissionsManager = strapi.
|
|
1379
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1462
1380
|
ability: ctx.state.userAbility,
|
|
1463
1381
|
model: RELEASE_MODEL_UID
|
|
1464
1382
|
});
|
|
1465
|
-
ctx.
|
|
1383
|
+
ctx.body = {
|
|
1466
1384
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1467
|
-
}
|
|
1385
|
+
};
|
|
1468
1386
|
},
|
|
1469
1387
|
async update(ctx) {
|
|
1470
1388
|
const user = ctx.state.user;
|
|
@@ -1473,7 +1391,7 @@ const releaseController = {
|
|
|
1473
1391
|
await validateRelease(releaseArgs);
|
|
1474
1392
|
const releaseService = getService("release", { strapi });
|
|
1475
1393
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1476
|
-
const permissionsManager = strapi.
|
|
1394
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1477
1395
|
ability: ctx.state.userAbility,
|
|
1478
1396
|
model: RELEASE_MODEL_UID
|
|
1479
1397
|
});
|
|
@@ -1490,18 +1408,18 @@ const releaseController = {
|
|
|
1490
1408
|
};
|
|
1491
1409
|
},
|
|
1492
1410
|
async publish(ctx) {
|
|
1411
|
+
const user = ctx.state.user;
|
|
1493
1412
|
const id = ctx.params.id;
|
|
1494
1413
|
const releaseService = getService("release", { strapi });
|
|
1495
|
-
const
|
|
1496
|
-
const release2 = await releaseService.publish(id);
|
|
1414
|
+
const release2 = await releaseService.publish(id, { user });
|
|
1497
1415
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1498
|
-
|
|
1416
|
+
releaseService.countActions({
|
|
1499
1417
|
filters: {
|
|
1500
1418
|
release: id,
|
|
1501
1419
|
type: "publish"
|
|
1502
1420
|
}
|
|
1503
1421
|
}),
|
|
1504
|
-
|
|
1422
|
+
releaseService.countActions({
|
|
1505
1423
|
filters: {
|
|
1506
1424
|
release: id,
|
|
1507
1425
|
type: "unpublish"
|
|
@@ -1519,30 +1437,27 @@ const releaseController = {
|
|
|
1519
1437
|
}
|
|
1520
1438
|
};
|
|
1521
1439
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1440
|
+
entry: utils.yup.object().shape({
|
|
1441
|
+
id: utils.yup.strapiID().required(),
|
|
1442
|
+
contentType: utils.yup.string().required()
|
|
1443
|
+
}).required(),
|
|
1525
1444
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1526
1445
|
});
|
|
1527
1446
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1528
1447
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1529
1448
|
});
|
|
1530
|
-
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1531
|
-
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1532
|
-
});
|
|
1533
1449
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1534
1450
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1535
|
-
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1536
1451
|
const releaseActionController = {
|
|
1537
1452
|
async create(ctx) {
|
|
1538
1453
|
const releaseId = ctx.params.releaseId;
|
|
1539
1454
|
const releaseActionArgs = ctx.request.body;
|
|
1540
1455
|
await validateReleaseAction(releaseActionArgs);
|
|
1541
|
-
const
|
|
1542
|
-
const releaseAction2 = await
|
|
1543
|
-
ctx.
|
|
1456
|
+
const releaseService = getService("release", { strapi });
|
|
1457
|
+
const releaseAction2 = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1458
|
+
ctx.body = {
|
|
1544
1459
|
data: releaseAction2
|
|
1545
|
-
}
|
|
1460
|
+
};
|
|
1546
1461
|
},
|
|
1547
1462
|
async createMany(ctx) {
|
|
1548
1463
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1550,12 +1465,14 @@ const releaseActionController = {
|
|
|
1550
1465
|
await Promise.all(
|
|
1551
1466
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1552
1467
|
);
|
|
1553
|
-
const
|
|
1468
|
+
const releaseService = getService("release", { strapi });
|
|
1554
1469
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1555
1470
|
const releaseActions2 = await Promise.all(
|
|
1556
1471
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1557
1472
|
try {
|
|
1558
|
-
const action = await
|
|
1473
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs, {
|
|
1474
|
+
disableUpdateReleaseStatus: true
|
|
1475
|
+
});
|
|
1559
1476
|
return action;
|
|
1560
1477
|
} catch (error) {
|
|
1561
1478
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1568,51 +1485,46 @@ const releaseActionController = {
|
|
|
1568
1485
|
return releaseActions2;
|
|
1569
1486
|
});
|
|
1570
1487
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1571
|
-
|
|
1488
|
+
if (newReleaseActions.length > 0) {
|
|
1489
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1490
|
+
}
|
|
1491
|
+
ctx.body = {
|
|
1572
1492
|
data: newReleaseActions,
|
|
1573
1493
|
meta: {
|
|
1574
1494
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1575
1495
|
totalEntries: releaseActions.length
|
|
1576
1496
|
}
|
|
1577
|
-
}
|
|
1497
|
+
};
|
|
1578
1498
|
},
|
|
1579
1499
|
async findMany(ctx) {
|
|
1580
1500
|
const releaseId = ctx.params.releaseId;
|
|
1581
|
-
const permissionsManager = strapi.
|
|
1501
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1582
1502
|
ability: ctx.state.userAbility,
|
|
1583
1503
|
model: RELEASE_ACTION_MODEL_UID
|
|
1584
1504
|
});
|
|
1585
|
-
await validateFindManyActionsParams(ctx.query);
|
|
1586
|
-
if (ctx.query.groupBy) {
|
|
1587
|
-
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1588
|
-
ctx.badRequest("Invalid groupBy parameter");
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1592
|
-
delete ctx.query.groupBy;
|
|
1593
1505
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1594
|
-
const
|
|
1595
|
-
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,
|
|
1596
1509
|
...query
|
|
1597
1510
|
});
|
|
1598
1511
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1599
1512
|
if (acc[action.contentType]) {
|
|
1600
1513
|
return acc;
|
|
1601
1514
|
}
|
|
1602
|
-
const contentTypePermissionsManager = strapi.
|
|
1515
|
+
const contentTypePermissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1603
1516
|
ability: ctx.state.userAbility,
|
|
1604
1517
|
model: action.contentType
|
|
1605
1518
|
});
|
|
1606
1519
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1607
1520
|
return acc;
|
|
1608
1521
|
}, {});
|
|
1609
|
-
const sanitizedResults = await utils.
|
|
1522
|
+
const sanitizedResults = await utils.mapAsync(results, async (action) => ({
|
|
1610
1523
|
...action,
|
|
1611
|
-
entry:
|
|
1524
|
+
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1612
1525
|
}));
|
|
1613
|
-
const groupedData = await
|
|
1614
|
-
const contentTypes2 =
|
|
1615
|
-
const releaseService = getService("release", { strapi });
|
|
1526
|
+
const groupedData = await releaseService.groupActions(sanitizedResults, query.groupBy);
|
|
1527
|
+
const contentTypes2 = releaseService.getContentTypeModelsFromActions(results);
|
|
1616
1528
|
const components = await releaseService.getAllComponents();
|
|
1617
1529
|
ctx.body = {
|
|
1618
1530
|
data: groupedData,
|
|
@@ -1628,8 +1540,8 @@ const releaseActionController = {
|
|
|
1628
1540
|
const releaseId = ctx.params.releaseId;
|
|
1629
1541
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1630
1542
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1631
|
-
const
|
|
1632
|
-
const updatedAction = await
|
|
1543
|
+
const releaseService = getService("release", { strapi });
|
|
1544
|
+
const updatedAction = await releaseService.updateAction(
|
|
1633
1545
|
actionId,
|
|
1634
1546
|
releaseId,
|
|
1635
1547
|
releaseActionUpdateArgs
|
|
@@ -1641,36 +1553,14 @@ const releaseActionController = {
|
|
|
1641
1553
|
async delete(ctx) {
|
|
1642
1554
|
const actionId = ctx.params.actionId;
|
|
1643
1555
|
const releaseId = ctx.params.releaseId;
|
|
1644
|
-
const
|
|
1645
|
-
const deletedReleaseAction = await
|
|
1556
|
+
const releaseService = getService("release", { strapi });
|
|
1557
|
+
const deletedReleaseAction = await releaseService.deleteAction(actionId, releaseId);
|
|
1646
1558
|
ctx.body = {
|
|
1647
1559
|
data: deletedReleaseAction
|
|
1648
1560
|
};
|
|
1649
1561
|
}
|
|
1650
1562
|
};
|
|
1651
|
-
const
|
|
1652
|
-
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1653
|
-
}).required().noUnknown();
|
|
1654
|
-
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1655
|
-
const settingsController = {
|
|
1656
|
-
async find(ctx) {
|
|
1657
|
-
const settingsService = getService("settings", { strapi });
|
|
1658
|
-
const settings2 = await settingsService.find();
|
|
1659
|
-
ctx.body = { data: settings2 };
|
|
1660
|
-
},
|
|
1661
|
-
async update(ctx) {
|
|
1662
|
-
const settingsBody = ctx.request.body;
|
|
1663
|
-
const settings2 = await validateSettings(settingsBody);
|
|
1664
|
-
const settingsService = getService("settings", { strapi });
|
|
1665
|
-
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1666
|
-
ctx.body = { data: updatedSettings };
|
|
1667
|
-
}
|
|
1668
|
-
};
|
|
1669
|
-
const controllers = {
|
|
1670
|
-
release: releaseController,
|
|
1671
|
-
"release-action": releaseActionController,
|
|
1672
|
-
settings: settingsController
|
|
1673
|
-
};
|
|
1563
|
+
const controllers = { release: releaseController, "release-action": releaseActionController };
|
|
1674
1564
|
const release = {
|
|
1675
1565
|
type: "admin",
|
|
1676
1566
|
routes: [
|
|
@@ -1690,22 +1580,6 @@ const release = {
|
|
|
1690
1580
|
]
|
|
1691
1581
|
}
|
|
1692
1582
|
},
|
|
1693
|
-
{
|
|
1694
|
-
method: "GET",
|
|
1695
|
-
path: "/getByDocumentAttached",
|
|
1696
|
-
handler: "release.findByDocumentAttached",
|
|
1697
|
-
config: {
|
|
1698
|
-
policies: [
|
|
1699
|
-
"admin::isAuthenticatedAdmin",
|
|
1700
|
-
{
|
|
1701
|
-
name: "admin::hasPermissions",
|
|
1702
|
-
config: {
|
|
1703
|
-
actions: ["plugin::content-releases.read"]
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1706
|
-
]
|
|
1707
|
-
}
|
|
1708
|
-
},
|
|
1709
1583
|
{
|
|
1710
1584
|
method: "POST",
|
|
1711
1585
|
path: "/",
|
|
@@ -1725,7 +1599,7 @@ const release = {
|
|
|
1725
1599
|
{
|
|
1726
1600
|
method: "GET",
|
|
1727
1601
|
path: "/",
|
|
1728
|
-
handler: "release.
|
|
1602
|
+
handler: "release.findMany",
|
|
1729
1603
|
config: {
|
|
1730
1604
|
policies: [
|
|
1731
1605
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1889,50 +1763,13 @@ const releaseAction = {
|
|
|
1889
1763
|
}
|
|
1890
1764
|
]
|
|
1891
1765
|
};
|
|
1892
|
-
const settings = {
|
|
1893
|
-
type: "admin",
|
|
1894
|
-
routes: [
|
|
1895
|
-
{
|
|
1896
|
-
method: "GET",
|
|
1897
|
-
path: "/settings",
|
|
1898
|
-
handler: "settings.find",
|
|
1899
|
-
config: {
|
|
1900
|
-
policies: [
|
|
1901
|
-
"admin::isAuthenticatedAdmin",
|
|
1902
|
-
{
|
|
1903
|
-
name: "admin::hasPermissions",
|
|
1904
|
-
config: {
|
|
1905
|
-
actions: ["plugin::content-releases.settings.read"]
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
]
|
|
1909
|
-
}
|
|
1910
|
-
},
|
|
1911
|
-
{
|
|
1912
|
-
method: "PUT",
|
|
1913
|
-
path: "/settings",
|
|
1914
|
-
handler: "settings.update",
|
|
1915
|
-
config: {
|
|
1916
|
-
policies: [
|
|
1917
|
-
"admin::isAuthenticatedAdmin",
|
|
1918
|
-
{
|
|
1919
|
-
name: "admin::hasPermissions",
|
|
1920
|
-
config: {
|
|
1921
|
-
actions: ["plugin::content-releases.settings.update"]
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
|
-
]
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
]
|
|
1928
|
-
};
|
|
1929
1766
|
const routes = {
|
|
1930
|
-
settings,
|
|
1931
1767
|
release,
|
|
1932
1768
|
"release-action": releaseAction
|
|
1933
1769
|
};
|
|
1770
|
+
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1934
1771
|
const getPlugin = () => {
|
|
1935
|
-
if (
|
|
1772
|
+
if (features.isEnabled("cms-content-releases")) {
|
|
1936
1773
|
return {
|
|
1937
1774
|
register,
|
|
1938
1775
|
bootstrap,
|