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