@strapi/content-releases 0.0.0-experimental.c592deb623aed3f74ef7fdacfad9757ed59d34f7 → 0.0.0-experimental.c95cecbc9ed31c3bd68eff1ae5fa4b64f2a5020e
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-Db0aPjrG.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 +639 -826
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +639 -827
- package/dist/server/index.mjs.map +1 -1
- package/package.json +38 -32
- package/strapi-server.js +3 -0
- package/dist/_chunks/App-Db0aPjrG.mjs.map +0 -1
- package/dist/_chunks/App-xHZkNTlJ.js +0 -1395
- package/dist/_chunks/App-xHZkNTlJ.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-C3rlM6Kf.mjs +0 -178
- package/dist/_chunks/ReleasesSettingsPage-C3rlM6Kf.mjs.map +0 -1
- package/dist/_chunks/ReleasesSettingsPage-DxEYftwd.js +0 -178
- package/dist/_chunks/ReleasesSettingsPage-DxEYftwd.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-CulHY6KM.js +0 -1377
- package/dist/_chunks/index-CulHY6KM.js.map +0 -1
- package/dist/_chunks/index-Dj_bL2s7.mjs +0 -1358
- package/dist/_chunks/index-Dj_bL2s7.mjs.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 -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
|
+
},
|
|
475
328
|
/**
|
|
476
|
-
* deleteMany
|
|
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
|
+
},
|
|
340
|
+
/**
|
|
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
|
|
@@ -837,229 +1037,16 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
837
1037
|
return {
|
|
838
1038
|
release: null,
|
|
839
1039
|
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, { 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
|
|
1040
|
+
};
|
|
963
1041
|
}
|
|
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
1042
|
});
|
|
983
|
-
if (
|
|
984
|
-
throw
|
|
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" ? 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,167 +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
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
});
|
|
1345
|
-
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 };
|
|
1346
1298
|
} else {
|
|
1347
|
-
const
|
|
1348
|
-
|
|
1349
|
-
|
|
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,
|
|
1350
1305
|
actions: {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1306
|
+
meta: {
|
|
1307
|
+
count: actions.count
|
|
1308
|
+
}
|
|
1354
1309
|
}
|
|
1355
|
-
}
|
|
1310
|
+
};
|
|
1356
1311
|
});
|
|
1357
|
-
const
|
|
1312
|
+
const pendingReleasesCount = await strapi.query(RELEASE_MODEL_UID).count({
|
|
1358
1313
|
where: {
|
|
1359
|
-
$or: [
|
|
1360
|
-
{
|
|
1361
|
-
id: {
|
|
1362
|
-
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1363
|
-
}
|
|
1364
|
-
},
|
|
1365
|
-
{
|
|
1366
|
-
actions: null
|
|
1367
|
-
}
|
|
1368
|
-
],
|
|
1369
1314
|
releasedAt: null
|
|
1370
1315
|
}
|
|
1371
1316
|
});
|
|
1372
|
-
ctx.body = { data:
|
|
1317
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1373
1318
|
}
|
|
1374
1319
|
},
|
|
1375
|
-
async findPage(ctx) {
|
|
1376
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1377
|
-
ability: ctx.state.userAbility,
|
|
1378
|
-
model: RELEASE_MODEL_UID
|
|
1379
|
-
});
|
|
1380
|
-
await permissionsManager.validateQuery(ctx.query);
|
|
1381
|
-
const releaseService = getService("release", { strapi });
|
|
1382
|
-
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1383
|
-
const { results, pagination } = await releaseService.findPage(query);
|
|
1384
|
-
const data = results.map((release2) => {
|
|
1385
|
-
const { actions, ...releaseData } = release2;
|
|
1386
|
-
return {
|
|
1387
|
-
...releaseData,
|
|
1388
|
-
actions: {
|
|
1389
|
-
meta: {
|
|
1390
|
-
count: actions.count
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
};
|
|
1394
|
-
});
|
|
1395
|
-
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1396
|
-
where: {
|
|
1397
|
-
releasedAt: null
|
|
1398
|
-
}
|
|
1399
|
-
});
|
|
1400
|
-
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1401
|
-
},
|
|
1402
1320
|
async findOne(ctx) {
|
|
1403
1321
|
const id = ctx.params.id;
|
|
1404
1322
|
const releaseService = getService("release", { strapi });
|
|
1405
|
-
const releaseActionService = getService("release-action", { strapi });
|
|
1406
1323
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1407
1324
|
if (!release2) {
|
|
1408
1325
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1409
1326
|
}
|
|
1410
|
-
const count = await
|
|
1327
|
+
const count = await releaseService.countActions({
|
|
1411
1328
|
filters: {
|
|
1412
1329
|
release: id
|
|
1413
1330
|
}
|
|
1414
1331
|
});
|
|
1415
1332
|
const sanitizedRelease = {
|
|
1416
1333
|
...release2,
|
|
1417
|
-
createdBy: release2.createdBy ? strapi.
|
|
1334
|
+
createdBy: release2.createdBy ? strapi.admin.services.user.sanitizeUser(release2.createdBy) : null
|
|
1418
1335
|
};
|
|
1419
1336
|
const data = {
|
|
1420
1337
|
...sanitizedRelease,
|
|
@@ -1427,39 +1344,22 @@ const releaseController = {
|
|
|
1427
1344
|
ctx.body = { data };
|
|
1428
1345
|
},
|
|
1429
1346
|
async mapEntriesToReleases(ctx) {
|
|
1430
|
-
const { contentTypeUid,
|
|
1431
|
-
if (!contentTypeUid || !
|
|
1347
|
+
const { contentTypeUid, entriesIds } = ctx.query;
|
|
1348
|
+
if (!contentTypeUid || !entriesIds) {
|
|
1432
1349
|
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1433
1350
|
}
|
|
1434
1351
|
const releaseService = getService("release", { strapi });
|
|
1435
|
-
const releasesWithActions = await releaseService.
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
contentType: contentTypeUid,
|
|
1440
|
-
entryDocumentId: {
|
|
1441
|
-
$in: documentIds
|
|
1442
|
-
},
|
|
1443
|
-
locale
|
|
1444
|
-
}
|
|
1445
|
-
},
|
|
1446
|
-
populate: {
|
|
1447
|
-
actions: true
|
|
1448
|
-
}
|
|
1449
|
-
});
|
|
1352
|
+
const releasesWithActions = await releaseService.findManyWithContentTypeEntryAttached(
|
|
1353
|
+
contentTypeUid,
|
|
1354
|
+
entriesIds
|
|
1355
|
+
);
|
|
1450
1356
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1451
1357
|
(acc, release2) => {
|
|
1452
1358
|
release2.actions.forEach((action) => {
|
|
1453
|
-
if (action.
|
|
1454
|
-
|
|
1455
|
-
}
|
|
1456
|
-
if (locale && action.locale !== locale) {
|
|
1457
|
-
return;
|
|
1458
|
-
}
|
|
1459
|
-
if (!acc[action.entryDocumentId]) {
|
|
1460
|
-
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 }];
|
|
1461
1361
|
} else {
|
|
1462
|
-
acc[action.
|
|
1362
|
+
acc[action.entry.id].push({ id: release2.id, name: release2.name });
|
|
1463
1363
|
}
|
|
1464
1364
|
});
|
|
1465
1365
|
return acc;
|
|
@@ -1476,13 +1376,13 @@ const releaseController = {
|
|
|
1476
1376
|
await validateRelease(releaseArgs);
|
|
1477
1377
|
const releaseService = getService("release", { strapi });
|
|
1478
1378
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1479
|
-
const permissionsManager = strapi.
|
|
1379
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1480
1380
|
ability: ctx.state.userAbility,
|
|
1481
1381
|
model: RELEASE_MODEL_UID
|
|
1482
1382
|
});
|
|
1483
|
-
ctx.
|
|
1383
|
+
ctx.body = {
|
|
1484
1384
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1485
|
-
}
|
|
1385
|
+
};
|
|
1486
1386
|
},
|
|
1487
1387
|
async update(ctx) {
|
|
1488
1388
|
const user = ctx.state.user;
|
|
@@ -1491,7 +1391,7 @@ const releaseController = {
|
|
|
1491
1391
|
await validateRelease(releaseArgs);
|
|
1492
1392
|
const releaseService = getService("release", { strapi });
|
|
1493
1393
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1494
|
-
const permissionsManager = strapi.
|
|
1394
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1495
1395
|
ability: ctx.state.userAbility,
|
|
1496
1396
|
model: RELEASE_MODEL_UID
|
|
1497
1397
|
});
|
|
@@ -1508,18 +1408,18 @@ const releaseController = {
|
|
|
1508
1408
|
};
|
|
1509
1409
|
},
|
|
1510
1410
|
async publish(ctx) {
|
|
1411
|
+
const user = ctx.state.user;
|
|
1511
1412
|
const id = ctx.params.id;
|
|
1512
1413
|
const releaseService = getService("release", { strapi });
|
|
1513
|
-
const
|
|
1514
|
-
const release2 = await releaseService.publish(id);
|
|
1414
|
+
const release2 = await releaseService.publish(id, { user });
|
|
1515
1415
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1516
|
-
|
|
1416
|
+
releaseService.countActions({
|
|
1517
1417
|
filters: {
|
|
1518
1418
|
release: id,
|
|
1519
1419
|
type: "publish"
|
|
1520
1420
|
}
|
|
1521
1421
|
}),
|
|
1522
|
-
|
|
1422
|
+
releaseService.countActions({
|
|
1523
1423
|
filters: {
|
|
1524
1424
|
release: id,
|
|
1525
1425
|
type: "unpublish"
|
|
@@ -1537,30 +1437,27 @@ const releaseController = {
|
|
|
1537
1437
|
}
|
|
1538
1438
|
};
|
|
1539
1439
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1440
|
+
entry: utils.yup.object().shape({
|
|
1441
|
+
id: utils.yup.strapiID().required(),
|
|
1442
|
+
contentType: utils.yup.string().required()
|
|
1443
|
+
}).required(),
|
|
1543
1444
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1544
1445
|
});
|
|
1545
1446
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1546
1447
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1547
1448
|
});
|
|
1548
|
-
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1549
|
-
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1550
|
-
});
|
|
1551
1449
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1552
1450
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1553
|
-
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1554
1451
|
const releaseActionController = {
|
|
1555
1452
|
async create(ctx) {
|
|
1556
1453
|
const releaseId = ctx.params.releaseId;
|
|
1557
1454
|
const releaseActionArgs = ctx.request.body;
|
|
1558
1455
|
await validateReleaseAction(releaseActionArgs);
|
|
1559
|
-
const
|
|
1560
|
-
const releaseAction2 = await
|
|
1561
|
-
ctx.
|
|
1456
|
+
const releaseService = getService("release", { strapi });
|
|
1457
|
+
const releaseAction2 = await releaseService.createAction(releaseId, releaseActionArgs);
|
|
1458
|
+
ctx.body = {
|
|
1562
1459
|
data: releaseAction2
|
|
1563
|
-
}
|
|
1460
|
+
};
|
|
1564
1461
|
},
|
|
1565
1462
|
async createMany(ctx) {
|
|
1566
1463
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1568,13 +1465,12 @@ const releaseActionController = {
|
|
|
1568
1465
|
await Promise.all(
|
|
1569
1466
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1570
1467
|
);
|
|
1571
|
-
const releaseActionService = getService("release-action", { strapi });
|
|
1572
1468
|
const releaseService = getService("release", { strapi });
|
|
1573
1469
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1574
1470
|
const releaseActions2 = await Promise.all(
|
|
1575
1471
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1576
1472
|
try {
|
|
1577
|
-
const action = await
|
|
1473
|
+
const action = await releaseService.createAction(releaseId, releaseActionArgs, {
|
|
1578
1474
|
disableUpdateReleaseStatus: true
|
|
1579
1475
|
});
|
|
1580
1476
|
return action;
|
|
@@ -1592,51 +1488,43 @@ const releaseActionController = {
|
|
|
1592
1488
|
if (newReleaseActions.length > 0) {
|
|
1593
1489
|
releaseService.updateReleaseStatus(releaseId);
|
|
1594
1490
|
}
|
|
1595
|
-
ctx.
|
|
1491
|
+
ctx.body = {
|
|
1596
1492
|
data: newReleaseActions,
|
|
1597
1493
|
meta: {
|
|
1598
1494
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1599
1495
|
totalEntries: releaseActions.length
|
|
1600
1496
|
}
|
|
1601
|
-
}
|
|
1497
|
+
};
|
|
1602
1498
|
},
|
|
1603
1499
|
async findMany(ctx) {
|
|
1604
1500
|
const releaseId = ctx.params.releaseId;
|
|
1605
|
-
const permissionsManager = strapi.
|
|
1501
|
+
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1606
1502
|
ability: ctx.state.userAbility,
|
|
1607
1503
|
model: RELEASE_ACTION_MODEL_UID
|
|
1608
1504
|
});
|
|
1609
|
-
await validateFindManyActionsParams(ctx.query);
|
|
1610
|
-
if (ctx.query.groupBy) {
|
|
1611
|
-
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1612
|
-
ctx.badRequest("Invalid groupBy parameter");
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1616
|
-
delete ctx.query.groupBy;
|
|
1617
1505
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1618
|
-
const
|
|
1619
|
-
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,
|
|
1620
1509
|
...query
|
|
1621
1510
|
});
|
|
1622
1511
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1623
1512
|
if (acc[action.contentType]) {
|
|
1624
1513
|
return acc;
|
|
1625
1514
|
}
|
|
1626
|
-
const contentTypePermissionsManager = strapi.
|
|
1515
|
+
const contentTypePermissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
|
1627
1516
|
ability: ctx.state.userAbility,
|
|
1628
1517
|
model: action.contentType
|
|
1629
1518
|
});
|
|
1630
1519
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1631
1520
|
return acc;
|
|
1632
1521
|
}, {});
|
|
1633
|
-
const sanitizedResults = await utils.
|
|
1522
|
+
const sanitizedResults = await utils.mapAsync(results, async (action) => ({
|
|
1634
1523
|
...action,
|
|
1635
|
-
entry:
|
|
1524
|
+
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1636
1525
|
}));
|
|
1637
|
-
const groupedData = await
|
|
1638
|
-
const contentTypes2 =
|
|
1639
|
-
const releaseService = getService("release", { strapi });
|
|
1526
|
+
const groupedData = await releaseService.groupActions(sanitizedResults, query.groupBy);
|
|
1527
|
+
const contentTypes2 = releaseService.getContentTypeModelsFromActions(results);
|
|
1640
1528
|
const components = await releaseService.getAllComponents();
|
|
1641
1529
|
ctx.body = {
|
|
1642
1530
|
data: groupedData,
|
|
@@ -1652,8 +1540,8 @@ const releaseActionController = {
|
|
|
1652
1540
|
const releaseId = ctx.params.releaseId;
|
|
1653
1541
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1654
1542
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1655
|
-
const
|
|
1656
|
-
const updatedAction = await
|
|
1543
|
+
const releaseService = getService("release", { strapi });
|
|
1544
|
+
const updatedAction = await releaseService.updateAction(
|
|
1657
1545
|
actionId,
|
|
1658
1546
|
releaseId,
|
|
1659
1547
|
releaseActionUpdateArgs
|
|
@@ -1665,36 +1553,14 @@ const releaseActionController = {
|
|
|
1665
1553
|
async delete(ctx) {
|
|
1666
1554
|
const actionId = ctx.params.actionId;
|
|
1667
1555
|
const releaseId = ctx.params.releaseId;
|
|
1668
|
-
const
|
|
1669
|
-
const deletedReleaseAction = await
|
|
1556
|
+
const releaseService = getService("release", { strapi });
|
|
1557
|
+
const deletedReleaseAction = await releaseService.deleteAction(actionId, releaseId);
|
|
1670
1558
|
ctx.body = {
|
|
1671
1559
|
data: deletedReleaseAction
|
|
1672
1560
|
};
|
|
1673
1561
|
}
|
|
1674
1562
|
};
|
|
1675
|
-
const
|
|
1676
|
-
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1677
|
-
}).required().noUnknown();
|
|
1678
|
-
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1679
|
-
const settingsController = {
|
|
1680
|
-
async find(ctx) {
|
|
1681
|
-
const settingsService = getService("settings", { strapi });
|
|
1682
|
-
const settings2 = await settingsService.find();
|
|
1683
|
-
ctx.body = { data: settings2 };
|
|
1684
|
-
},
|
|
1685
|
-
async update(ctx) {
|
|
1686
|
-
const settingsBody = ctx.request.body;
|
|
1687
|
-
const settings2 = await validateSettings(settingsBody);
|
|
1688
|
-
const settingsService = getService("settings", { strapi });
|
|
1689
|
-
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1690
|
-
ctx.body = { data: updatedSettings };
|
|
1691
|
-
}
|
|
1692
|
-
};
|
|
1693
|
-
const controllers = {
|
|
1694
|
-
release: releaseController,
|
|
1695
|
-
"release-action": releaseActionController,
|
|
1696
|
-
settings: settingsController
|
|
1697
|
-
};
|
|
1563
|
+
const controllers = { release: releaseController, "release-action": releaseActionController };
|
|
1698
1564
|
const release = {
|
|
1699
1565
|
type: "admin",
|
|
1700
1566
|
routes: [
|
|
@@ -1714,22 +1580,6 @@ const release = {
|
|
|
1714
1580
|
]
|
|
1715
1581
|
}
|
|
1716
1582
|
},
|
|
1717
|
-
{
|
|
1718
|
-
method: "GET",
|
|
1719
|
-
path: "/getByDocumentAttached",
|
|
1720
|
-
handler: "release.findByDocumentAttached",
|
|
1721
|
-
config: {
|
|
1722
|
-
policies: [
|
|
1723
|
-
"admin::isAuthenticatedAdmin",
|
|
1724
|
-
{
|
|
1725
|
-
name: "admin::hasPermissions",
|
|
1726
|
-
config: {
|
|
1727
|
-
actions: ["plugin::content-releases.read"]
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
]
|
|
1731
|
-
}
|
|
1732
|
-
},
|
|
1733
1583
|
{
|
|
1734
1584
|
method: "POST",
|
|
1735
1585
|
path: "/",
|
|
@@ -1749,7 +1599,7 @@ const release = {
|
|
|
1749
1599
|
{
|
|
1750
1600
|
method: "GET",
|
|
1751
1601
|
path: "/",
|
|
1752
|
-
handler: "release.
|
|
1602
|
+
handler: "release.findMany",
|
|
1753
1603
|
config: {
|
|
1754
1604
|
policies: [
|
|
1755
1605
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1913,50 +1763,13 @@ const releaseAction = {
|
|
|
1913
1763
|
}
|
|
1914
1764
|
]
|
|
1915
1765
|
};
|
|
1916
|
-
const settings = {
|
|
1917
|
-
type: "admin",
|
|
1918
|
-
routes: [
|
|
1919
|
-
{
|
|
1920
|
-
method: "GET",
|
|
1921
|
-
path: "/settings",
|
|
1922
|
-
handler: "settings.find",
|
|
1923
|
-
config: {
|
|
1924
|
-
policies: [
|
|
1925
|
-
"admin::isAuthenticatedAdmin",
|
|
1926
|
-
{
|
|
1927
|
-
name: "admin::hasPermissions",
|
|
1928
|
-
config: {
|
|
1929
|
-
actions: ["plugin::content-releases.settings.read"]
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
]
|
|
1933
|
-
}
|
|
1934
|
-
},
|
|
1935
|
-
{
|
|
1936
|
-
method: "PUT",
|
|
1937
|
-
path: "/settings",
|
|
1938
|
-
handler: "settings.update",
|
|
1939
|
-
config: {
|
|
1940
|
-
policies: [
|
|
1941
|
-
"admin::isAuthenticatedAdmin",
|
|
1942
|
-
{
|
|
1943
|
-
name: "admin::hasPermissions",
|
|
1944
|
-
config: {
|
|
1945
|
-
actions: ["plugin::content-releases.settings.update"]
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
]
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
]
|
|
1952
|
-
};
|
|
1953
1766
|
const routes = {
|
|
1954
|
-
settings,
|
|
1955
1767
|
release,
|
|
1956
1768
|
"release-action": releaseAction
|
|
1957
1769
|
};
|
|
1770
|
+
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1958
1771
|
const getPlugin = () => {
|
|
1959
|
-
if (
|
|
1772
|
+
if (features.isEnabled("cms-content-releases")) {
|
|
1960
1773
|
return {
|
|
1961
1774
|
register,
|
|
1962
1775
|
bootstrap,
|