@strapi/content-releases 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.e8d8fc824d0f6a695b2a9ebaa4680ed21c3645ca
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-BsUSTHVD.mjs → App-CiZCkScI.mjs} +643 -428
- package/dist/_chunks/App-CiZCkScI.mjs.map +1 -0
- package/dist/_chunks/{App-CXRpb2hi.js → App-SGjO5UPV.js} +682 -470
- package/dist/_chunks/App-SGjO5UPV.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-Be3acS2L.js → PurchaseContentReleases--qQepXpP.js} +2 -2
- package/dist/_chunks/PurchaseContentReleases--qQepXpP.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-_MxP6-Dt.mjs → PurchaseContentReleases-D-n-w-st.mjs} +2 -2
- package/dist/_chunks/{PurchaseContentReleases-_MxP6-Dt.mjs.map → PurchaseContentReleases-D-n-w-st.mjs.map} +1 -1
- 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-DtFJ5ViE.js → en-BWPPsSH-.js} +18 -2
- package/dist/_chunks/en-BWPPsSH-.js.map +1 -0
- package/dist/_chunks/{en-B9Ur3VsE.mjs → en-D9Q4YW03.mjs} +18 -2
- package/dist/_chunks/en-D9Q4YW03.mjs.map +1 -0
- package/dist/_chunks/{index-DJLIZdZv.mjs → index-BjvFfTtA.mjs} +751 -605
- package/dist/_chunks/index-BjvFfTtA.mjs.map +1 -0
- package/dist/_chunks/{index-B6-lic1Q.js → index-CyU534vL.js} +739 -596
- 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/ReleaseActionMenu.d.ts +3 -3
- package/dist/admin/src/components/{CMReleasesContainer.d.ts → ReleaseActionModal.d.ts} +3 -1
- 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 +53 -370
- 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 +889 -614
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +889 -613
- package/dist/server/index.mjs.map +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 +6 -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 +7 -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/index.d.ts +64 -49
- 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.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 +36 -38
- 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 +6 -41
- package/dist/server/src/services/release.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 +1 -1
- package/dist/server/src/services/validation.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +29 -8
- 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 +9 -7
- 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 -23
- package/dist/_chunks/App-BsUSTHVD.mjs.map +0 -1
- package/dist/_chunks/App-CXRpb2hi.js.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +0 -1
- package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
- package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
- package/dist/_chunks/index-B6-lic1Q.js.map +0 -1
- package/dist/_chunks/index-DJLIZdZv.mjs.map +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,6 +70,23 @@ 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 = {
|
|
@@ -79,16 +95,13 @@ const ALLOWED_WEBHOOK_EVENTS = {
|
|
|
79
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
|
}
|
|
@@ -278,9 +336,42 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
278
336
|
}
|
|
279
337
|
}
|
|
280
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
|
+
};
|
|
281
371
|
const register = async ({ strapi: strapi2 }) => {
|
|
282
372
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
283
373
|
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
374
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
284
375
|
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
285
376
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
286
377
|
}
|
|
@@ -290,6 +381,105 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
290
381
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
291
382
|
}
|
|
292
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
|
+
};
|
|
293
483
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
294
484
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
295
485
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
@@ -297,115 +487,29 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
297
487
|
);
|
|
298
488
|
strapi2.db.lifecycles.subscribe({
|
|
299
489
|
models: contentTypesWithDraftAndPublish,
|
|
300
|
-
async afterDelete(event) {
|
|
301
|
-
try {
|
|
302
|
-
const { model, result } = event;
|
|
303
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
304
|
-
const { id } = result;
|
|
305
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
306
|
-
where: {
|
|
307
|
-
actions: {
|
|
308
|
-
target_type: model.uid,
|
|
309
|
-
target_id: id
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
314
|
-
where: {
|
|
315
|
-
target_type: model.uid,
|
|
316
|
-
target_id: id
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
for (const release2 of releases) {
|
|
320
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
} catch (error) {
|
|
324
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
/**
|
|
328
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
329
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
330
|
-
*/
|
|
331
|
-
async beforeDeleteMany(event) {
|
|
332
|
-
const { model, params } = event;
|
|
333
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
334
|
-
const { where } = params;
|
|
335
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
336
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
490
|
/**
|
|
340
|
-
*
|
|
341
|
-
* 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
|
|
342
492
|
*/
|
|
343
493
|
async afterDeleteMany(event) {
|
|
344
494
|
try {
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
target_id: {
|
|
353
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
359
|
-
where: {
|
|
360
|
-
target_type: model.uid,
|
|
361
|
-
target_id: {
|
|
362
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
363
|
-
}
|
|
364
|
-
}
|
|
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 }
|
|
365
502
|
});
|
|
366
|
-
for (const release2 of releases) {
|
|
367
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
368
|
-
}
|
|
369
503
|
}
|
|
370
504
|
} catch (error) {
|
|
371
505
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
372
506
|
error
|
|
373
507
|
});
|
|
374
508
|
}
|
|
375
|
-
},
|
|
376
|
-
async afterUpdate(event) {
|
|
377
|
-
try {
|
|
378
|
-
const { model, result } = event;
|
|
379
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
380
|
-
const isEntryValid = await getEntryValidStatus(model.uid, result, {
|
|
381
|
-
strapi: strapi2
|
|
382
|
-
});
|
|
383
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
384
|
-
where: {
|
|
385
|
-
target_type: model.uid,
|
|
386
|
-
target_id: result.id
|
|
387
|
-
},
|
|
388
|
-
data: {
|
|
389
|
-
isEntryValid
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
393
|
-
where: {
|
|
394
|
-
actions: {
|
|
395
|
-
target_type: model.uid,
|
|
396
|
-
target_id: result.id
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
for (const release2 of releases) {
|
|
401
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
} catch (error) {
|
|
405
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
406
|
-
}
|
|
407
509
|
}
|
|
408
510
|
});
|
|
511
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
512
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
409
513
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
410
514
|
strapi2.log.error(
|
|
411
515
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -497,15 +601,13 @@ const schema = {
|
|
|
497
601
|
enum: ["publish", "unpublish"],
|
|
498
602
|
required: true
|
|
499
603
|
},
|
|
500
|
-
entry: {
|
|
501
|
-
type: "relation",
|
|
502
|
-
relation: "morphToOne",
|
|
503
|
-
configurable: false
|
|
504
|
-
},
|
|
505
604
|
contentType: {
|
|
506
605
|
type: "string",
|
|
507
606
|
required: true
|
|
508
607
|
},
|
|
608
|
+
entryDocumentId: {
|
|
609
|
+
type: "string"
|
|
610
|
+
},
|
|
509
611
|
locale: {
|
|
510
612
|
type: "string"
|
|
511
613
|
},
|
|
@@ -527,18 +629,6 @@ const contentTypes = {
|
|
|
527
629
|
release: release$1,
|
|
528
630
|
"release-action": releaseAction$1
|
|
529
631
|
};
|
|
530
|
-
const getGroupName = (queryValue) => {
|
|
531
|
-
switch (queryValue) {
|
|
532
|
-
case "contentType":
|
|
533
|
-
return "contentType.displayName";
|
|
534
|
-
case "action":
|
|
535
|
-
return "type";
|
|
536
|
-
case "locale":
|
|
537
|
-
return ___default.default.getOr("No locale", "locale.name");
|
|
538
|
-
default:
|
|
539
|
-
return "contentType.displayName";
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
632
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
543
633
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
544
634
|
strapi2.eventHub.emit(event, {
|
|
@@ -547,93 +637,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
547
637
|
release: release2
|
|
548
638
|
});
|
|
549
639
|
};
|
|
550
|
-
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
551
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
552
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
553
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
554
|
-
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
555
|
-
try {
|
|
556
|
-
if (actionType === "publish") {
|
|
557
|
-
await entityManagerService.publish(entry, uid);
|
|
558
|
-
} else {
|
|
559
|
-
await entityManagerService.unpublish(entry, uid);
|
|
560
|
-
}
|
|
561
|
-
} catch (error) {
|
|
562
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
563
|
-
;
|
|
564
|
-
else {
|
|
565
|
-
throw error;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
570
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
571
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
572
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
573
|
-
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
574
|
-
filters: {
|
|
575
|
-
id: {
|
|
576
|
-
$in: entriesToPublishIds
|
|
577
|
-
}
|
|
578
|
-
},
|
|
579
|
-
populate
|
|
580
|
-
});
|
|
581
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
582
|
-
filters: {
|
|
583
|
-
id: {
|
|
584
|
-
$in: entriestoUnpublishIds
|
|
585
|
-
}
|
|
586
|
-
},
|
|
587
|
-
populate
|
|
588
|
-
});
|
|
589
|
-
if (entriesToPublish.length > 0) {
|
|
590
|
-
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
591
|
-
}
|
|
592
|
-
if (entriesToUnpublish.length > 0) {
|
|
593
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
640
|
const getFormattedActions = async (releaseId) => {
|
|
597
641
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
598
642
|
where: {
|
|
599
643
|
release: {
|
|
600
644
|
id: releaseId
|
|
601
645
|
}
|
|
602
|
-
},
|
|
603
|
-
populate: {
|
|
604
|
-
entry: {
|
|
605
|
-
fields: ["id"]
|
|
606
|
-
}
|
|
607
646
|
}
|
|
608
647
|
});
|
|
609
648
|
if (actions.length === 0) {
|
|
610
649
|
throw new utils.errors.ValidationError("No entries to publish");
|
|
611
650
|
}
|
|
612
|
-
const
|
|
613
|
-
const singleTypeActions = [];
|
|
651
|
+
const formattedActions = {};
|
|
614
652
|
for (const action of actions) {
|
|
615
653
|
const contentTypeUid = action.contentType;
|
|
616
|
-
if (
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
if (action.type === "publish") {
|
|
624
|
-
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
625
|
-
} else {
|
|
626
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
627
|
-
}
|
|
628
|
-
} else {
|
|
629
|
-
singleTypeActions.push({
|
|
630
|
-
uid: contentTypeUid,
|
|
631
|
-
action: action.type,
|
|
632
|
-
id: action.entry.id
|
|
633
|
-
});
|
|
654
|
+
if (!formattedActions[contentTypeUid]) {
|
|
655
|
+
formattedActions[contentTypeUid] = {
|
|
656
|
+
publish: [],
|
|
657
|
+
unpublish: []
|
|
658
|
+
};
|
|
634
659
|
}
|
|
660
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
661
|
+
documentId: action.entryDocumentId,
|
|
662
|
+
locale: action.locale
|
|
663
|
+
});
|
|
635
664
|
}
|
|
636
|
-
return
|
|
665
|
+
return formattedActions;
|
|
637
666
|
};
|
|
638
667
|
return {
|
|
639
668
|
async create(releaseData, { user }) {
|
|
@@ -680,91 +709,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
680
709
|
}
|
|
681
710
|
});
|
|
682
711
|
},
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
688
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
689
|
-
where: {
|
|
690
|
-
actions: {
|
|
691
|
-
target_type: contentTypeUid,
|
|
692
|
-
target_id: {
|
|
693
|
-
$in: entries
|
|
694
|
-
}
|
|
695
|
-
},
|
|
696
|
-
releasedAt: {
|
|
697
|
-
$null: true
|
|
698
|
-
}
|
|
699
|
-
},
|
|
700
|
-
populate: {
|
|
701
|
-
// Filter the action to get only the content type entry
|
|
702
|
-
actions: {
|
|
703
|
-
where: {
|
|
704
|
-
target_type: contentTypeUid,
|
|
705
|
-
target_id: {
|
|
706
|
-
$in: entries
|
|
707
|
-
}
|
|
708
|
-
},
|
|
709
|
-
populate: {
|
|
710
|
-
entry: {
|
|
711
|
-
select: ["id"]
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
return releases.map((release2) => {
|
|
718
|
-
if (release2.actions?.length) {
|
|
719
|
-
const actionsForEntry = release2.actions;
|
|
720
|
-
delete release2.actions;
|
|
721
|
-
return {
|
|
722
|
-
...release2,
|
|
723
|
-
actions: actionsForEntry
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
return release2;
|
|
727
|
-
});
|
|
728
|
-
},
|
|
729
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
730
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
731
|
-
where: {
|
|
732
|
-
releasedAt: {
|
|
733
|
-
$null: true
|
|
734
|
-
},
|
|
735
|
-
actions: {
|
|
736
|
-
target_type: contentTypeUid,
|
|
737
|
-
target_id: entryId
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
742
|
-
where: {
|
|
743
|
-
$or: [
|
|
744
|
-
{
|
|
745
|
-
id: {
|
|
746
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
747
|
-
}
|
|
748
|
-
},
|
|
749
|
-
{
|
|
750
|
-
actions: null
|
|
751
|
-
}
|
|
752
|
-
],
|
|
753
|
-
releasedAt: {
|
|
754
|
-
$null: true
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
});
|
|
758
|
-
return releases.map((release2) => {
|
|
759
|
-
if (release2.actions?.length) {
|
|
760
|
-
const [actionForEntry] = release2.actions;
|
|
761
|
-
delete release2.actions;
|
|
762
|
-
return {
|
|
763
|
-
...release2,
|
|
764
|
-
action: actionForEntry
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
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
|
|
768
716
|
});
|
|
769
717
|
},
|
|
770
718
|
async update(id, releaseData, { user }) {
|
|
@@ -800,14 +748,218 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
800
748
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
801
749
|
return updatedRelease;
|
|
802
750
|
},
|
|
803
|
-
async
|
|
804
|
-
const
|
|
751
|
+
async getAllComponents() {
|
|
752
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
753
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
754
|
+
const componentsMap = components.reduce(
|
|
755
|
+
(acc, component) => {
|
|
756
|
+
acc[component.uid] = component;
|
|
757
|
+
return acc;
|
|
758
|
+
},
|
|
759
|
+
{}
|
|
760
|
+
);
|
|
761
|
+
return componentsMap;
|
|
762
|
+
},
|
|
763
|
+
async delete(releaseId) {
|
|
764
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
765
|
+
where: { id: releaseId },
|
|
766
|
+
populate: {
|
|
767
|
+
actions: {
|
|
768
|
+
select: ["id"]
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
if (!release2) {
|
|
773
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
774
|
+
}
|
|
775
|
+
if (release2.releasedAt) {
|
|
776
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
777
|
+
}
|
|
778
|
+
await strapi2.db.transaction(async () => {
|
|
779
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
780
|
+
where: {
|
|
781
|
+
id: {
|
|
782
|
+
$in: release2.actions.map((action) => action.id)
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
787
|
+
where: {
|
|
788
|
+
id: releaseId
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
if (release2.scheduledAt) {
|
|
793
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
794
|
+
await schedulingService.cancel(release2.id);
|
|
795
|
+
}
|
|
796
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
797
|
+
return release2;
|
|
798
|
+
},
|
|
799
|
+
async publish(releaseId) {
|
|
800
|
+
const {
|
|
801
|
+
release: release2,
|
|
802
|
+
error
|
|
803
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
804
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
805
|
+
if (!lockedRelease) {
|
|
806
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
807
|
+
}
|
|
808
|
+
if (lockedRelease.releasedAt) {
|
|
809
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
810
|
+
}
|
|
811
|
+
if (lockedRelease.status === "failed") {
|
|
812
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
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
|
+
)
|
|
828
|
+
);
|
|
829
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
830
|
+
where: {
|
|
831
|
+
id: releaseId
|
|
832
|
+
},
|
|
833
|
+
data: {
|
|
834
|
+
status: "done",
|
|
835
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
839
|
+
isPublished: true,
|
|
840
|
+
release: release22
|
|
841
|
+
});
|
|
842
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
843
|
+
return { release: release22, error: null };
|
|
844
|
+
} catch (error2) {
|
|
845
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
846
|
+
isPublished: false,
|
|
847
|
+
error: error2
|
|
848
|
+
});
|
|
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", {
|
|
805
949
|
strapi: strapi2
|
|
806
950
|
});
|
|
807
951
|
await Promise.all([
|
|
808
|
-
|
|
952
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
809
953
|
validateUniqueEntry(releaseId, action)
|
|
810
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
|
+
}
|
|
811
963
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
812
964
|
if (!release2) {
|
|
813
965
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -815,28 +967,30 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
815
967
|
if (release2.releasedAt) {
|
|
816
968
|
throw new utils.errors.ValidationError("Release already published");
|
|
817
969
|
}
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
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;
|
|
821
980
|
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
822
981
|
data: {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
isEntryValid,
|
|
827
|
-
entry: {
|
|
828
|
-
id: entry.id,
|
|
829
|
-
__type: entry.contentType,
|
|
830
|
-
__pivot: { field: "entry" }
|
|
831
|
-
},
|
|
832
|
-
release: releaseId
|
|
982
|
+
...action,
|
|
983
|
+
release: release2.id,
|
|
984
|
+
isEntryValid: actionStatus
|
|
833
985
|
},
|
|
834
|
-
populate: { release: { select: ["id"] }
|
|
986
|
+
populate: { release: { select: ["id"] } }
|
|
835
987
|
});
|
|
836
|
-
|
|
988
|
+
if (!disableUpdateReleaseStatus) {
|
|
989
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
990
|
+
}
|
|
837
991
|
return releaseAction2;
|
|
838
992
|
},
|
|
839
|
-
async
|
|
993
|
+
async findPage(releaseId, query) {
|
|
840
994
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
841
995
|
where: { id: releaseId },
|
|
842
996
|
select: ["id"]
|
|
@@ -845,21 +999,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
845
999
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
846
1000
|
}
|
|
847
1001
|
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
848
|
-
|
|
1002
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
849
1003
|
...dbQuery,
|
|
850
|
-
populate: {
|
|
851
|
-
entry: {
|
|
852
|
-
populate: "*"
|
|
853
|
-
}
|
|
854
|
-
},
|
|
855
1004
|
where: {
|
|
856
1005
|
release: releaseId
|
|
857
1006
|
}
|
|
858
1007
|
});
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
+
};
|
|
863
1031
|
},
|
|
864
1032
|
async groupActions(actions, groupBy) {
|
|
865
1033
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -868,8 +1036,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
868
1036
|
}
|
|
869
1037
|
return acc;
|
|
870
1038
|
}, []);
|
|
871
|
-
const allReleaseContentTypesDictionary = await
|
|
872
|
-
const allLocalesDictionary = await
|
|
1039
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1040
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
873
1041
|
const formattedData = actions.map((action) => {
|
|
874
1042
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
875
1043
|
return {
|
|
@@ -881,165 +1049,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
881
1049
|
uid: action.contentType
|
|
882
1050
|
}
|
|
883
1051
|
};
|
|
884
|
-
});
|
|
885
|
-
const groupName = getGroupName(groupBy);
|
|
886
|
-
return ___default.default.groupBy(groupName)(formattedData);
|
|
887
|
-
},
|
|
888
|
-
async getLocalesDataForActions() {
|
|
889
|
-
if (!strapi2.plugin("i18n")) {
|
|
890
|
-
return {};
|
|
891
|
-
}
|
|
892
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
893
|
-
return allLocales.reduce((acc, locale) => {
|
|
894
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
895
|
-
return acc;
|
|
896
|
-
}, {});
|
|
897
|
-
},
|
|
898
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
899
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
900
|
-
const contentTypesData = {};
|
|
901
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
902
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
903
|
-
uid: contentTypeUid
|
|
904
|
-
});
|
|
905
|
-
contentTypesData[contentTypeUid] = {
|
|
906
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
907
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
return contentTypesData;
|
|
911
|
-
},
|
|
912
|
-
getContentTypeModelsFromActions(actions) {
|
|
913
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
914
|
-
if (!acc.includes(action.contentType)) {
|
|
915
|
-
acc.push(action.contentType);
|
|
916
|
-
}
|
|
917
|
-
return acc;
|
|
918
|
-
}, []);
|
|
919
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
920
|
-
(acc, contentTypeUid) => {
|
|
921
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
922
|
-
return acc;
|
|
923
|
-
},
|
|
924
|
-
{}
|
|
925
|
-
);
|
|
926
|
-
return contentTypeModelsMap;
|
|
927
|
-
},
|
|
928
|
-
async getAllComponents() {
|
|
929
|
-
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
930
|
-
const components = await contentManagerComponentsService.findAllComponents();
|
|
931
|
-
const componentsMap = components.reduce(
|
|
932
|
-
(acc, component) => {
|
|
933
|
-
acc[component.uid] = component;
|
|
934
|
-
return acc;
|
|
935
|
-
},
|
|
936
|
-
{}
|
|
937
|
-
);
|
|
938
|
-
return componentsMap;
|
|
939
|
-
},
|
|
940
|
-
async delete(releaseId) {
|
|
941
|
-
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
942
|
-
where: { id: releaseId },
|
|
943
|
-
populate: {
|
|
944
|
-
actions: {
|
|
945
|
-
select: ["id"]
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
});
|
|
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
|
-
await strapi2.db.transaction(async () => {
|
|
956
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
957
|
-
where: {
|
|
958
|
-
id: {
|
|
959
|
-
$in: release2.actions.map((action) => action.id)
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
});
|
|
963
|
-
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
964
|
-
where: {
|
|
965
|
-
id: releaseId
|
|
966
|
-
}
|
|
967
|
-
});
|
|
968
|
-
});
|
|
969
|
-
if (release2.scheduledAt) {
|
|
970
|
-
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
971
|
-
await schedulingService.cancel(release2.id);
|
|
972
|
-
}
|
|
973
|
-
strapi2.telemetry.send("didDeleteContentRelease");
|
|
974
|
-
return release2;
|
|
1052
|
+
});
|
|
1053
|
+
const groupName = getGroupName(groupBy);
|
|
1054
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
975
1055
|
},
|
|
976
|
-
async
|
|
977
|
-
const {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
981
|
-
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
982
|
-
if (!lockedRelease) {
|
|
983
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
984
|
-
}
|
|
985
|
-
if (lockedRelease.releasedAt) {
|
|
986
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
987
|
-
}
|
|
988
|
-
if (lockedRelease.status === "failed") {
|
|
989
|
-
throw new utils.errors.ValidationError("Release failed to publish");
|
|
1056
|
+
async getContentTypeModelsFromActions(actions) {
|
|
1057
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1058
|
+
if (!acc.includes(action.contentType)) {
|
|
1059
|
+
acc.push(action.contentType);
|
|
990
1060
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
await publishCollectionTypeAction(
|
|
1001
|
-
uid,
|
|
1002
|
-
collectionTypeActions[uid].entriesToPublishIds,
|
|
1003
|
-
collectionTypeActions[uid].entriesToUnpublishIds
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
});
|
|
1007
|
-
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1008
|
-
where: {
|
|
1009
|
-
id: releaseId
|
|
1010
|
-
},
|
|
1011
|
-
data: {
|
|
1012
|
-
status: "done",
|
|
1013
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
1014
|
-
}
|
|
1015
|
-
});
|
|
1016
|
-
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
1017
|
-
isPublished: true,
|
|
1018
|
-
release: release22
|
|
1019
|
-
});
|
|
1020
|
-
strapi2.telemetry.send("didPublishContentRelease");
|
|
1021
|
-
return { release: release22, error: null };
|
|
1022
|
-
} catch (error2) {
|
|
1023
|
-
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
1024
|
-
isPublished: false,
|
|
1025
|
-
error: error2
|
|
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"
|
|
1026
1070
|
});
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
release: null,
|
|
1032
|
-
error: error2
|
|
1071
|
+
acc[contentTypeUid] = {
|
|
1072
|
+
...contentTypeModel,
|
|
1073
|
+
hasReviewWorkflow: !!workflow,
|
|
1074
|
+
stageRequiredToPublish: workflow?.stageRequiredToPublish
|
|
1033
1075
|
};
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
return release2;
|
|
1076
|
+
return acc;
|
|
1077
|
+
},
|
|
1078
|
+
{}
|
|
1079
|
+
);
|
|
1080
|
+
return contentTypeModelsMap;
|
|
1040
1081
|
},
|
|
1041
|
-
async
|
|
1042
|
-
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({
|
|
1043
1088
|
where: {
|
|
1044
1089
|
id: actionId,
|
|
1045
1090
|
release: {
|
|
@@ -1048,17 +1093,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1048
1093
|
$null: true
|
|
1049
1094
|
}
|
|
1050
1095
|
}
|
|
1051
|
-
}
|
|
1052
|
-
data: update
|
|
1096
|
+
}
|
|
1053
1097
|
});
|
|
1054
|
-
if (!
|
|
1098
|
+
if (!action) {
|
|
1055
1099
|
throw new utils.errors.NotFoundError(
|
|
1056
1100
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1057
1101
|
);
|
|
1058
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);
|
|
1059
1129
|
return updatedAction;
|
|
1060
1130
|
},
|
|
1061
|
-
async
|
|
1131
|
+
async delete(actionId, releaseId) {
|
|
1062
1132
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1063
1133
|
where: {
|
|
1064
1134
|
id: actionId,
|
|
@@ -1075,51 +1145,56 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1075
1145
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1076
1146
|
);
|
|
1077
1147
|
}
|
|
1078
|
-
|
|
1148
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1079
1149
|
return deletedAction;
|
|
1080
1150
|
},
|
|
1081
|
-
async
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
}
|
|
1093
|
-
})
|
|
1094
|
-
]);
|
|
1095
|
-
if (totalActions > 0) {
|
|
1096
|
-
if (invalidActions > 0) {
|
|
1097
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1098
|
-
where: {
|
|
1099
|
-
id: releaseId
|
|
1100
|
-
},
|
|
1101
|
-
data: {
|
|
1102
|
-
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
|
|
1103
1162
|
}
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
|
|
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({
|
|
1107
1178
|
where: {
|
|
1108
|
-
id:
|
|
1179
|
+
id: action.id
|
|
1109
1180
|
},
|
|
1110
1181
|
data: {
|
|
1111
|
-
|
|
1182
|
+
isEntryValid: isValid
|
|
1112
1183
|
}
|
|
1113
1184
|
});
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
where: {
|
|
1117
|
-
id: releaseId
|
|
1118
|
-
},
|
|
1119
|
-
data: {
|
|
1120
|
-
status: "empty"
|
|
1185
|
+
if (!releasesUpdated.includes(action.release.id)) {
|
|
1186
|
+
releasesUpdated.push(action.release.id);
|
|
1121
1187
|
}
|
|
1188
|
+
return {
|
|
1189
|
+
id: action.id,
|
|
1190
|
+
isEntryValid: isValid
|
|
1191
|
+
};
|
|
1122
1192
|
});
|
|
1193
|
+
if (releasesUpdated.length > 0) {
|
|
1194
|
+
await utils.async.map(releasesUpdated, async (releaseId) => {
|
|
1195
|
+
await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1123
1198
|
}
|
|
1124
1199
|
};
|
|
1125
1200
|
};
|
|
@@ -1135,30 +1210,35 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1135
1210
|
where: {
|
|
1136
1211
|
id: releaseId
|
|
1137
1212
|
},
|
|
1138
|
-
populate: {
|
|
1213
|
+
populate: {
|
|
1214
|
+
actions: true
|
|
1215
|
+
}
|
|
1139
1216
|
});
|
|
1140
1217
|
if (!release2) {
|
|
1141
1218
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1142
1219
|
}
|
|
1143
1220
|
const isEntryInRelease = release2.actions.some(
|
|
1144
|
-
(action) =>
|
|
1221
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1145
1222
|
);
|
|
1146
1223
|
if (isEntryInRelease) {
|
|
1147
1224
|
throw new AlreadyOnReleaseError(
|
|
1148
|
-
`Entry with
|
|
1225
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1149
1226
|
);
|
|
1150
1227
|
}
|
|
1151
1228
|
},
|
|
1152
|
-
|
|
1229
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1153
1230
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1154
1231
|
if (!contentType) {
|
|
1155
1232
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1156
1233
|
}
|
|
1157
|
-
if (!contentType
|
|
1234
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1158
1235
|
throw new utils.errors.ValidationError(
|
|
1159
1236
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1160
1237
|
);
|
|
1161
1238
|
}
|
|
1239
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1240
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1241
|
+
}
|
|
1162
1242
|
},
|
|
1163
1243
|
async validatePendingReleasesLimit() {
|
|
1164
1244
|
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
@@ -1247,78 +1327,165 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1247
1327
|
}
|
|
1248
1328
|
};
|
|
1249
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
|
+
};
|
|
1250
1351
|
const services = {
|
|
1251
1352
|
release: createReleaseService,
|
|
1353
|
+
"release-action": createReleaseActionService,
|
|
1252
1354
|
"release-validation": createReleaseValidationService,
|
|
1253
|
-
scheduling: createSchedulingService
|
|
1355
|
+
scheduling: createSchedulingService,
|
|
1356
|
+
settings: createSettingsService
|
|
1254
1357
|
};
|
|
1255
|
-
const RELEASE_SCHEMA =
|
|
1256
|
-
name:
|
|
1257
|
-
scheduledAt:
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
otherwise: yup__namespace.string().nullable()
|
|
1263
|
-
}),
|
|
1264
|
-
timezone: yup__namespace.string().when("isScheduled", {
|
|
1265
|
-
is: true,
|
|
1266
|
-
then: yup__namespace.string().required().nullable(),
|
|
1267
|
-
otherwise: yup__namespace.string().nullable()
|
|
1268
|
-
}),
|
|
1269
|
-
date: yup__namespace.string().when("isScheduled", {
|
|
1270
|
-
is: true,
|
|
1271
|
-
then: yup__namespace.string().required().nullable(),
|
|
1272
|
-
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()
|
|
1273
1365
|
})
|
|
1274
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();
|
|
1275
1373
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1374
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1375
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1376
|
+
);
|
|
1276
1377
|
const releaseController = {
|
|
1277
|
-
|
|
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) {
|
|
1278
1384
|
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1279
1385
|
ability: ctx.state.userAbility,
|
|
1280
1386
|
model: RELEASE_MODEL_UID
|
|
1281
1387
|
});
|
|
1282
1388
|
await permissionsManager.validateQuery(ctx.query);
|
|
1283
1389
|
const releaseService = getService("release", { strapi });
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
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: {
|
|
1299
1413
|
actions: {
|
|
1300
|
-
|
|
1301
|
-
|
|
1414
|
+
fields: ["type"],
|
|
1415
|
+
filters: {
|
|
1416
|
+
contentType,
|
|
1417
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1418
|
+
locale: locale ?? null
|
|
1302
1419
|
}
|
|
1303
1420
|
}
|
|
1304
|
-
}
|
|
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
|
+
}
|
|
1305
1434
|
});
|
|
1306
|
-
const
|
|
1435
|
+
const releases = await releaseService.findMany({
|
|
1307
1436
|
where: {
|
|
1437
|
+
$or: [
|
|
1438
|
+
{
|
|
1439
|
+
id: {
|
|
1440
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
{
|
|
1444
|
+
actions: null
|
|
1445
|
+
}
|
|
1446
|
+
],
|
|
1308
1447
|
releasedAt: null
|
|
1309
1448
|
}
|
|
1310
1449
|
});
|
|
1311
|
-
ctx.body = { data
|
|
1450
|
+
ctx.body = { data: releases };
|
|
1312
1451
|
}
|
|
1313
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
|
+
},
|
|
1314
1480
|
async findOne(ctx) {
|
|
1315
1481
|
const id = ctx.params.id;
|
|
1316
1482
|
const releaseService = getService("release", { strapi });
|
|
1483
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1317
1484
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1318
1485
|
if (!release2) {
|
|
1319
1486
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1320
1487
|
}
|
|
1321
|
-
const count = await
|
|
1488
|
+
const count = await releaseActionService.countActions({
|
|
1322
1489
|
filters: {
|
|
1323
1490
|
release: id
|
|
1324
1491
|
}
|
|
@@ -1338,28 +1505,43 @@ const releaseController = {
|
|
|
1338
1505
|
ctx.body = { data };
|
|
1339
1506
|
},
|
|
1340
1507
|
async mapEntriesToReleases(ctx) {
|
|
1341
|
-
const { contentTypeUid,
|
|
1342
|
-
if (!contentTypeUid || !
|
|
1508
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1509
|
+
if (!contentTypeUid || !documentIds) {
|
|
1343
1510
|
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1344
1511
|
}
|
|
1345
1512
|
const releaseService = getService("release", { strapi });
|
|
1346
|
-
const releasesWithActions = await releaseService.
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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
|
+
});
|
|
1350
1528
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1351
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1352
1529
|
(acc, release2) => {
|
|
1353
1530
|
release2.actions.forEach((action) => {
|
|
1354
|
-
if (
|
|
1355
|
-
|
|
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 }];
|
|
1356
1539
|
} else {
|
|
1357
|
-
acc[action.
|
|
1540
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1358
1541
|
}
|
|
1359
1542
|
});
|
|
1360
1543
|
return acc;
|
|
1361
1544
|
},
|
|
1362
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1363
1545
|
{}
|
|
1364
1546
|
);
|
|
1365
1547
|
ctx.body = {
|
|
@@ -1404,18 +1586,18 @@ const releaseController = {
|
|
|
1404
1586
|
};
|
|
1405
1587
|
},
|
|
1406
1588
|
async publish(ctx) {
|
|
1407
|
-
const user = ctx.state.user;
|
|
1408
1589
|
const id = ctx.params.id;
|
|
1409
1590
|
const releaseService = getService("release", { strapi });
|
|
1410
|
-
const
|
|
1591
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1592
|
+
const release2 = await releaseService.publish(id);
|
|
1411
1593
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1412
|
-
|
|
1594
|
+
releaseActionService.countActions({
|
|
1413
1595
|
filters: {
|
|
1414
1596
|
release: id,
|
|
1415
1597
|
type: "publish"
|
|
1416
1598
|
}
|
|
1417
1599
|
}),
|
|
1418
|
-
|
|
1600
|
+
releaseActionService.countActions({
|
|
1419
1601
|
filters: {
|
|
1420
1602
|
release: id,
|
|
1421
1603
|
type: "unpublish"
|
|
@@ -1433,24 +1615,27 @@ const releaseController = {
|
|
|
1433
1615
|
}
|
|
1434
1616
|
};
|
|
1435
1617
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
}).required(),
|
|
1618
|
+
contentType: utils.yup.string().required(),
|
|
1619
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1620
|
+
locale: utils.yup.string(),
|
|
1440
1621
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1441
1622
|
});
|
|
1442
1623
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1443
1624
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1444
1625
|
});
|
|
1626
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1627
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1628
|
+
});
|
|
1445
1629
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1446
1630
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1631
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1447
1632
|
const releaseActionController = {
|
|
1448
1633
|
async create(ctx) {
|
|
1449
1634
|
const releaseId = ctx.params.releaseId;
|
|
1450
1635
|
const releaseActionArgs = ctx.request.body;
|
|
1451
1636
|
await validateReleaseAction(releaseActionArgs);
|
|
1452
|
-
const
|
|
1453
|
-
const releaseAction2 = await
|
|
1637
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1638
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1454
1639
|
ctx.created({
|
|
1455
1640
|
data: releaseAction2
|
|
1456
1641
|
});
|
|
@@ -1461,12 +1646,15 @@ const releaseActionController = {
|
|
|
1461
1646
|
await Promise.all(
|
|
1462
1647
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1463
1648
|
);
|
|
1649
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1464
1650
|
const releaseService = getService("release", { strapi });
|
|
1465
1651
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1466
1652
|
const releaseActions2 = await Promise.all(
|
|
1467
1653
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1468
1654
|
try {
|
|
1469
|
-
const action = await
|
|
1655
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1656
|
+
disableUpdateReleaseStatus: true
|
|
1657
|
+
});
|
|
1470
1658
|
return action;
|
|
1471
1659
|
} catch (error) {
|
|
1472
1660
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1479,6 +1667,9 @@ const releaseActionController = {
|
|
|
1479
1667
|
return releaseActions2;
|
|
1480
1668
|
});
|
|
1481
1669
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1670
|
+
if (newReleaseActions.length > 0) {
|
|
1671
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1672
|
+
}
|
|
1482
1673
|
ctx.created({
|
|
1483
1674
|
data: newReleaseActions,
|
|
1484
1675
|
meta: {
|
|
@@ -1493,10 +1684,17 @@ const releaseActionController = {
|
|
|
1493
1684
|
ability: ctx.state.userAbility,
|
|
1494
1685
|
model: RELEASE_ACTION_MODEL_UID
|
|
1495
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;
|
|
1496
1695
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1497
|
-
const
|
|
1498
|
-
const { results, pagination } = await
|
|
1499
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1696
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1697
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1500
1698
|
...query
|
|
1501
1699
|
});
|
|
1502
1700
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
@@ -1512,10 +1710,11 @@ const releaseActionController = {
|
|
|
1512
1710
|
}, {});
|
|
1513
1711
|
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1514
1712
|
...action,
|
|
1515
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1713
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1516
1714
|
}));
|
|
1517
|
-
const groupedData = await
|
|
1518
|
-
const contentTypes2 =
|
|
1715
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1716
|
+
const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
|
|
1717
|
+
const releaseService = getService("release", { strapi });
|
|
1519
1718
|
const components = await releaseService.getAllComponents();
|
|
1520
1719
|
ctx.body = {
|
|
1521
1720
|
data: groupedData,
|
|
@@ -1531,8 +1730,8 @@ const releaseActionController = {
|
|
|
1531
1730
|
const releaseId = ctx.params.releaseId;
|
|
1532
1731
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1533
1732
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1534
|
-
const
|
|
1535
|
-
const updatedAction = await
|
|
1733
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1734
|
+
const updatedAction = await releaseActionService.update(
|
|
1536
1735
|
actionId,
|
|
1537
1736
|
releaseId,
|
|
1538
1737
|
releaseActionUpdateArgs
|
|
@@ -1544,14 +1743,36 @@ const releaseActionController = {
|
|
|
1544
1743
|
async delete(ctx) {
|
|
1545
1744
|
const actionId = ctx.params.actionId;
|
|
1546
1745
|
const releaseId = ctx.params.releaseId;
|
|
1547
|
-
const
|
|
1548
|
-
const deletedReleaseAction = await
|
|
1746
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1747
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1549
1748
|
ctx.body = {
|
|
1550
1749
|
data: deletedReleaseAction
|
|
1551
1750
|
};
|
|
1552
1751
|
}
|
|
1553
1752
|
};
|
|
1554
|
-
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
|
+
};
|
|
1555
1776
|
const release = {
|
|
1556
1777
|
type: "admin",
|
|
1557
1778
|
routes: [
|
|
@@ -1571,6 +1792,22 @@ const release = {
|
|
|
1571
1792
|
]
|
|
1572
1793
|
}
|
|
1573
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
|
+
},
|
|
1574
1811
|
{
|
|
1575
1812
|
method: "POST",
|
|
1576
1813
|
path: "/",
|
|
@@ -1590,7 +1827,7 @@ const release = {
|
|
|
1590
1827
|
{
|
|
1591
1828
|
method: "GET",
|
|
1592
1829
|
path: "/",
|
|
1593
|
-
handler: "release.
|
|
1830
|
+
handler: "release.findPage",
|
|
1594
1831
|
config: {
|
|
1595
1832
|
policies: [
|
|
1596
1833
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1754,7 +1991,45 @@ const releaseAction = {
|
|
|
1754
1991
|
}
|
|
1755
1992
|
]
|
|
1756
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
|
+
};
|
|
1757
2031
|
const routes = {
|
|
2032
|
+
settings,
|
|
1758
2033
|
release,
|
|
1759
2034
|
"release-action": releaseAction
|
|
1760
2035
|
};
|