@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.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { contentTypes as contentTypes$1, async, setCreatorFields, errors,
|
|
1
|
+
import { contentTypes as contentTypes$1, async, setCreatorFields, errors, yup as yup$1, validateYupSchema } from "@strapi/utils";
|
|
2
2
|
import isEqual from "lodash/isEqual";
|
|
3
3
|
import { difference, keys } from "lodash";
|
|
4
4
|
import _ from "lodash/fp";
|
|
@@ -48,6 +48,23 @@ const ACTIONS = [
|
|
|
48
48
|
displayName: "Add an entry to a release",
|
|
49
49
|
uid: "create-action",
|
|
50
50
|
pluginName: "content-releases"
|
|
51
|
+
},
|
|
52
|
+
// Settings
|
|
53
|
+
{
|
|
54
|
+
uid: "settings.read",
|
|
55
|
+
section: "settings",
|
|
56
|
+
displayName: "Read",
|
|
57
|
+
category: "content releases",
|
|
58
|
+
subCategory: "options",
|
|
59
|
+
pluginName: "content-releases"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
uid: "settings.update",
|
|
63
|
+
section: "settings",
|
|
64
|
+
displayName: "Edit",
|
|
65
|
+
category: "content releases",
|
|
66
|
+
subCategory: "options",
|
|
67
|
+
pluginName: "content-releases"
|
|
51
68
|
}
|
|
52
69
|
];
|
|
53
70
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
@@ -56,16 +73,13 @@ const ALLOWED_WEBHOOK_EVENTS = {
|
|
|
56
73
|
const getService = (name, { strapi: strapi2 }) => {
|
|
57
74
|
return strapi2.plugin("content-releases").service(name);
|
|
58
75
|
};
|
|
59
|
-
const
|
|
76
|
+
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi: strapi2 }) => {
|
|
60
77
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
61
|
-
const populate = await populateBuilderService(
|
|
62
|
-
const entry = await strapi2
|
|
63
|
-
|
|
64
|
-
populate
|
|
65
|
-
});
|
|
66
|
-
return entry;
|
|
78
|
+
const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();
|
|
79
|
+
const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi: strapi2 });
|
|
80
|
+
return isEntryValid(contentType, entry, { strapi: strapi2 });
|
|
67
81
|
};
|
|
68
|
-
const
|
|
82
|
+
const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
69
83
|
try {
|
|
70
84
|
await strapi2.entityValidator.validateEntityCreation(
|
|
71
85
|
strapi2.getModel(contentTypeUid),
|
|
@@ -74,11 +88,54 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) =
|
|
|
74
88
|
// @ts-expect-error - FIXME: entity here is unnecessary
|
|
75
89
|
entry
|
|
76
90
|
);
|
|
91
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
92
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
93
|
+
populate: "stageRequiredToPublish"
|
|
94
|
+
});
|
|
95
|
+
if (workflow?.stageRequiredToPublish) {
|
|
96
|
+
return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;
|
|
97
|
+
}
|
|
77
98
|
return true;
|
|
78
99
|
} catch {
|
|
79
100
|
return false;
|
|
80
101
|
}
|
|
81
102
|
};
|
|
103
|
+
const getEntry = async ({
|
|
104
|
+
contentType,
|
|
105
|
+
documentId,
|
|
106
|
+
locale,
|
|
107
|
+
populate,
|
|
108
|
+
status = "draft"
|
|
109
|
+
}, { strapi: strapi2 }) => {
|
|
110
|
+
if (documentId) {
|
|
111
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
112
|
+
if (status === "published" && !entry) {
|
|
113
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
114
|
+
}
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
117
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
118
|
+
};
|
|
119
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
120
|
+
if (entry.publishedAt) {
|
|
121
|
+
return "published";
|
|
122
|
+
}
|
|
123
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
124
|
+
documentId: entry.documentId,
|
|
125
|
+
locale: entry.locale,
|
|
126
|
+
status: "published",
|
|
127
|
+
fields: ["updatedAt"]
|
|
128
|
+
});
|
|
129
|
+
if (!publishedEntry) {
|
|
130
|
+
return "draft";
|
|
131
|
+
}
|
|
132
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
133
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
134
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
135
|
+
return "modified";
|
|
136
|
+
}
|
|
137
|
+
return "published";
|
|
138
|
+
};
|
|
82
139
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
83
140
|
oldContentTypes,
|
|
84
141
|
contentTypes: contentTypes2
|
|
@@ -124,20 +181,22 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
124
181
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
125
182
|
for (const action of notValidatedActions) {
|
|
126
183
|
if (action.entry) {
|
|
127
|
-
const
|
|
128
|
-
|
|
184
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
185
|
+
{
|
|
186
|
+
contentType: action.contentType,
|
|
187
|
+
documentId: action.entryDocumentId,
|
|
188
|
+
locale: action.locale
|
|
189
|
+
},
|
|
190
|
+
{ strapi }
|
|
191
|
+
);
|
|
192
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
193
|
+
where: {
|
|
194
|
+
id: action.id
|
|
195
|
+
},
|
|
196
|
+
data: {
|
|
197
|
+
isEntryValid: isEntryValid2
|
|
198
|
+
}
|
|
129
199
|
});
|
|
130
|
-
if (populatedEntry) {
|
|
131
|
-
const isEntryValid = getEntryValidStatus(action.contentType, populatedEntry, { strapi });
|
|
132
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
133
|
-
where: {
|
|
134
|
-
id: action.id
|
|
135
|
-
},
|
|
136
|
-
data: {
|
|
137
|
-
isEntryValid
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
200
|
}
|
|
142
201
|
}
|
|
143
202
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -181,24 +240,24 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
181
240
|
}
|
|
182
241
|
});
|
|
183
242
|
await async.map(actions, async (action) => {
|
|
184
|
-
if (action.entry && action.release) {
|
|
185
|
-
const
|
|
186
|
-
|
|
243
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
244
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
245
|
+
{
|
|
246
|
+
contentType: contentTypeUID,
|
|
247
|
+
documentId: action.entryDocumentId,
|
|
248
|
+
locale: action.locale
|
|
249
|
+
},
|
|
250
|
+
{ strapi }
|
|
251
|
+
);
|
|
252
|
+
releasesAffected.add(action.release.id);
|
|
253
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
254
|
+
where: {
|
|
255
|
+
id: action.id
|
|
256
|
+
},
|
|
257
|
+
data: {
|
|
258
|
+
isEntryValid: isEntryValid2
|
|
259
|
+
}
|
|
187
260
|
});
|
|
188
|
-
if (populatedEntry) {
|
|
189
|
-
const isEntryValid = await getEntryValidStatus(contentTypeUID, populatedEntry, {
|
|
190
|
-
strapi
|
|
191
|
-
});
|
|
192
|
-
releasesAffected.add(action.release.id);
|
|
193
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
194
|
-
where: {
|
|
195
|
-
id: action.id
|
|
196
|
-
},
|
|
197
|
-
data: {
|
|
198
|
-
isEntryValid
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
261
|
}
|
|
203
262
|
});
|
|
204
263
|
}
|
|
@@ -255,9 +314,42 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
255
314
|
}
|
|
256
315
|
}
|
|
257
316
|
}
|
|
317
|
+
const addEntryDocumentToReleaseActions = {
|
|
318
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
319
|
+
async up(trx, db) {
|
|
320
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
321
|
+
if (!hasTable) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
325
|
+
if (hasPolymorphicColumn) {
|
|
326
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
327
|
+
"strapi_release_actions",
|
|
328
|
+
"entry_document_id"
|
|
329
|
+
);
|
|
330
|
+
if (!hasEntryDocumentIdColumn) {
|
|
331
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
332
|
+
table.string("entry_document_id");
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
336
|
+
async.map(releaseActions, async (action) => {
|
|
337
|
+
const { target_type, target_id } = action;
|
|
338
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
339
|
+
if (entry) {
|
|
340
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
async down() {
|
|
346
|
+
throw new Error("not implemented");
|
|
347
|
+
}
|
|
348
|
+
};
|
|
258
349
|
const register = async ({ strapi: strapi2 }) => {
|
|
259
350
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
260
351
|
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
352
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
261
353
|
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
262
354
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
263
355
|
}
|
|
@@ -267,6 +359,105 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
267
359
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
268
360
|
}
|
|
269
361
|
};
|
|
362
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
363
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
364
|
+
where: {
|
|
365
|
+
releasedAt: null,
|
|
366
|
+
actions: {
|
|
367
|
+
contentType,
|
|
368
|
+
entryDocumentId: entry.documentId,
|
|
369
|
+
locale: entry.locale
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
374
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).updateMany({
|
|
375
|
+
where: {
|
|
376
|
+
contentType,
|
|
377
|
+
entryDocumentId: entry.documentId,
|
|
378
|
+
locale: entry.locale
|
|
379
|
+
},
|
|
380
|
+
data: {
|
|
381
|
+
isEntryValid: entryStatus
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
for (const release2 of releases) {
|
|
385
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
389
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
390
|
+
where: {
|
|
391
|
+
actions: params
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
395
|
+
where: params
|
|
396
|
+
});
|
|
397
|
+
for (const release2 of releases) {
|
|
398
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
402
|
+
if (ctx.action !== "delete") {
|
|
403
|
+
return next();
|
|
404
|
+
}
|
|
405
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
406
|
+
return next();
|
|
407
|
+
}
|
|
408
|
+
const contentType = ctx.contentType.uid;
|
|
409
|
+
const { documentId, locale } = ctx.params;
|
|
410
|
+
const result = await next();
|
|
411
|
+
if (!result) {
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
try {
|
|
415
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
416
|
+
contentType,
|
|
417
|
+
entryDocumentId: documentId,
|
|
418
|
+
...locale !== "*" && { locale }
|
|
419
|
+
});
|
|
420
|
+
} catch (error) {
|
|
421
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
422
|
+
error
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return result;
|
|
426
|
+
};
|
|
427
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
428
|
+
if (ctx.action !== "update") {
|
|
429
|
+
return next();
|
|
430
|
+
}
|
|
431
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
432
|
+
return next();
|
|
433
|
+
}
|
|
434
|
+
const contentType = ctx.contentType.uid;
|
|
435
|
+
const result = await next();
|
|
436
|
+
if (!result) {
|
|
437
|
+
return result;
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
441
|
+
} catch (error) {
|
|
442
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
443
|
+
error
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
return result;
|
|
447
|
+
};
|
|
448
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
449
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
450
|
+
where: {
|
|
451
|
+
actions: params
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
455
|
+
where: params
|
|
456
|
+
});
|
|
457
|
+
for (const release2 of releases) {
|
|
458
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
270
461
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
271
462
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
272
463
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
@@ -274,115 +465,29 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
274
465
|
);
|
|
275
466
|
strapi2.db.lifecycles.subscribe({
|
|
276
467
|
models: contentTypesWithDraftAndPublish,
|
|
277
|
-
async afterDelete(event) {
|
|
278
|
-
try {
|
|
279
|
-
const { model, result } = event;
|
|
280
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
281
|
-
const { id } = result;
|
|
282
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
283
|
-
where: {
|
|
284
|
-
actions: {
|
|
285
|
-
target_type: model.uid,
|
|
286
|
-
target_id: id
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
291
|
-
where: {
|
|
292
|
-
target_type: model.uid,
|
|
293
|
-
target_id: id
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
for (const release2 of releases) {
|
|
297
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
} catch (error) {
|
|
301
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
302
|
-
}
|
|
303
|
-
},
|
|
304
|
-
/**
|
|
305
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
306
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
307
|
-
*/
|
|
308
|
-
async beforeDeleteMany(event) {
|
|
309
|
-
const { model, params } = event;
|
|
310
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
311
|
-
const { where } = params;
|
|
312
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
313
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
468
|
/**
|
|
317
|
-
*
|
|
318
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
469
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
319
470
|
*/
|
|
320
471
|
async afterDeleteMany(event) {
|
|
321
472
|
try {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
target_id: {
|
|
330
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
336
|
-
where: {
|
|
337
|
-
target_type: model.uid,
|
|
338
|
-
target_id: {
|
|
339
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
340
|
-
}
|
|
341
|
-
}
|
|
473
|
+
const model = strapi2.getModel(event.model.uid);
|
|
474
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
475
|
+
const { where } = event.params;
|
|
476
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
477
|
+
contentType: model.uid,
|
|
478
|
+
locale: where?.locale ?? null,
|
|
479
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
342
480
|
});
|
|
343
|
-
for (const release2 of releases) {
|
|
344
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
345
|
-
}
|
|
346
481
|
}
|
|
347
482
|
} catch (error) {
|
|
348
483
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
349
484
|
error
|
|
350
485
|
});
|
|
351
486
|
}
|
|
352
|
-
},
|
|
353
|
-
async afterUpdate(event) {
|
|
354
|
-
try {
|
|
355
|
-
const { model, result } = event;
|
|
356
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
357
|
-
const isEntryValid = await getEntryValidStatus(model.uid, result, {
|
|
358
|
-
strapi: strapi2
|
|
359
|
-
});
|
|
360
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
361
|
-
where: {
|
|
362
|
-
target_type: model.uid,
|
|
363
|
-
target_id: result.id
|
|
364
|
-
},
|
|
365
|
-
data: {
|
|
366
|
-
isEntryValid
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
370
|
-
where: {
|
|
371
|
-
actions: {
|
|
372
|
-
target_type: model.uid,
|
|
373
|
-
target_id: result.id
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
for (const release2 of releases) {
|
|
378
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
} catch (error) {
|
|
382
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
383
|
-
}
|
|
384
487
|
}
|
|
385
488
|
});
|
|
489
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
490
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
386
491
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
387
492
|
strapi2.log.error(
|
|
388
493
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -474,15 +579,13 @@ const schema = {
|
|
|
474
579
|
enum: ["publish", "unpublish"],
|
|
475
580
|
required: true
|
|
476
581
|
},
|
|
477
|
-
entry: {
|
|
478
|
-
type: "relation",
|
|
479
|
-
relation: "morphToOne",
|
|
480
|
-
configurable: false
|
|
481
|
-
},
|
|
482
582
|
contentType: {
|
|
483
583
|
type: "string",
|
|
484
584
|
required: true
|
|
485
585
|
},
|
|
586
|
+
entryDocumentId: {
|
|
587
|
+
type: "string"
|
|
588
|
+
},
|
|
486
589
|
locale: {
|
|
487
590
|
type: "string"
|
|
488
591
|
},
|
|
@@ -504,18 +607,6 @@ const contentTypes = {
|
|
|
504
607
|
release: release$1,
|
|
505
608
|
"release-action": releaseAction$1
|
|
506
609
|
};
|
|
507
|
-
const getGroupName = (queryValue) => {
|
|
508
|
-
switch (queryValue) {
|
|
509
|
-
case "contentType":
|
|
510
|
-
return "contentType.displayName";
|
|
511
|
-
case "action":
|
|
512
|
-
return "type";
|
|
513
|
-
case "locale":
|
|
514
|
-
return _.getOr("No locale", "locale.name");
|
|
515
|
-
default:
|
|
516
|
-
return "contentType.displayName";
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
610
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
520
611
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
521
612
|
strapi2.eventHub.emit(event, {
|
|
@@ -524,93 +615,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
524
615
|
release: release2
|
|
525
616
|
});
|
|
526
617
|
};
|
|
527
|
-
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
528
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
529
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
530
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
531
|
-
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
532
|
-
try {
|
|
533
|
-
if (actionType === "publish") {
|
|
534
|
-
await entityManagerService.publish(entry, uid);
|
|
535
|
-
} else {
|
|
536
|
-
await entityManagerService.unpublish(entry, uid);
|
|
537
|
-
}
|
|
538
|
-
} catch (error) {
|
|
539
|
-
if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
540
|
-
;
|
|
541
|
-
else {
|
|
542
|
-
throw error;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
547
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
548
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
549
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
550
|
-
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
551
|
-
filters: {
|
|
552
|
-
id: {
|
|
553
|
-
$in: entriesToPublishIds
|
|
554
|
-
}
|
|
555
|
-
},
|
|
556
|
-
populate
|
|
557
|
-
});
|
|
558
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
559
|
-
filters: {
|
|
560
|
-
id: {
|
|
561
|
-
$in: entriestoUnpublishIds
|
|
562
|
-
}
|
|
563
|
-
},
|
|
564
|
-
populate
|
|
565
|
-
});
|
|
566
|
-
if (entriesToPublish.length > 0) {
|
|
567
|
-
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
568
|
-
}
|
|
569
|
-
if (entriesToUnpublish.length > 0) {
|
|
570
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
618
|
const getFormattedActions = async (releaseId) => {
|
|
574
619
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
575
620
|
where: {
|
|
576
621
|
release: {
|
|
577
622
|
id: releaseId
|
|
578
623
|
}
|
|
579
|
-
},
|
|
580
|
-
populate: {
|
|
581
|
-
entry: {
|
|
582
|
-
fields: ["id"]
|
|
583
|
-
}
|
|
584
624
|
}
|
|
585
625
|
});
|
|
586
626
|
if (actions.length === 0) {
|
|
587
627
|
throw new errors.ValidationError("No entries to publish");
|
|
588
628
|
}
|
|
589
|
-
const
|
|
590
|
-
const singleTypeActions = [];
|
|
629
|
+
const formattedActions = {};
|
|
591
630
|
for (const action of actions) {
|
|
592
631
|
const contentTypeUid = action.contentType;
|
|
593
|
-
if (
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
|
-
if (action.type === "publish") {
|
|
601
|
-
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
602
|
-
} else {
|
|
603
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
604
|
-
}
|
|
605
|
-
} else {
|
|
606
|
-
singleTypeActions.push({
|
|
607
|
-
uid: contentTypeUid,
|
|
608
|
-
action: action.type,
|
|
609
|
-
id: action.entry.id
|
|
610
|
-
});
|
|
632
|
+
if (!formattedActions[contentTypeUid]) {
|
|
633
|
+
formattedActions[contentTypeUid] = {
|
|
634
|
+
publish: [],
|
|
635
|
+
unpublish: []
|
|
636
|
+
};
|
|
611
637
|
}
|
|
638
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
639
|
+
documentId: action.entryDocumentId,
|
|
640
|
+
locale: action.locale
|
|
641
|
+
});
|
|
612
642
|
}
|
|
613
|
-
return
|
|
643
|
+
return formattedActions;
|
|
614
644
|
};
|
|
615
645
|
return {
|
|
616
646
|
async create(releaseData, { user }) {
|
|
@@ -657,91 +687,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
657
687
|
}
|
|
658
688
|
});
|
|
659
689
|
},
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
666
|
-
where: {
|
|
667
|
-
actions: {
|
|
668
|
-
target_type: contentTypeUid,
|
|
669
|
-
target_id: {
|
|
670
|
-
$in: entries
|
|
671
|
-
}
|
|
672
|
-
},
|
|
673
|
-
releasedAt: {
|
|
674
|
-
$null: true
|
|
675
|
-
}
|
|
676
|
-
},
|
|
677
|
-
populate: {
|
|
678
|
-
// Filter the action to get only the content type entry
|
|
679
|
-
actions: {
|
|
680
|
-
where: {
|
|
681
|
-
target_type: contentTypeUid,
|
|
682
|
-
target_id: {
|
|
683
|
-
$in: entries
|
|
684
|
-
}
|
|
685
|
-
},
|
|
686
|
-
populate: {
|
|
687
|
-
entry: {
|
|
688
|
-
select: ["id"]
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
return releases.map((release2) => {
|
|
695
|
-
if (release2.actions?.length) {
|
|
696
|
-
const actionsForEntry = release2.actions;
|
|
697
|
-
delete release2.actions;
|
|
698
|
-
return {
|
|
699
|
-
...release2,
|
|
700
|
-
actions: actionsForEntry
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
return release2;
|
|
704
|
-
});
|
|
705
|
-
},
|
|
706
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
707
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
708
|
-
where: {
|
|
709
|
-
releasedAt: {
|
|
710
|
-
$null: true
|
|
711
|
-
},
|
|
712
|
-
actions: {
|
|
713
|
-
target_type: contentTypeUid,
|
|
714
|
-
target_id: entryId
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
719
|
-
where: {
|
|
720
|
-
$or: [
|
|
721
|
-
{
|
|
722
|
-
id: {
|
|
723
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
724
|
-
}
|
|
725
|
-
},
|
|
726
|
-
{
|
|
727
|
-
actions: null
|
|
728
|
-
}
|
|
729
|
-
],
|
|
730
|
-
releasedAt: {
|
|
731
|
-
$null: true
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
return releases.map((release2) => {
|
|
736
|
-
if (release2.actions?.length) {
|
|
737
|
-
const [actionForEntry] = release2.actions;
|
|
738
|
-
delete release2.actions;
|
|
739
|
-
return {
|
|
740
|
-
...release2,
|
|
741
|
-
action: actionForEntry
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
return release2;
|
|
690
|
+
findMany(query) {
|
|
691
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
692
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
693
|
+
...dbQuery
|
|
745
694
|
});
|
|
746
695
|
},
|
|
747
696
|
async update(id, releaseData, { user }) {
|
|
@@ -777,14 +726,218 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
777
726
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
778
727
|
return updatedRelease;
|
|
779
728
|
},
|
|
780
|
-
async
|
|
781
|
-
const
|
|
729
|
+
async getAllComponents() {
|
|
730
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
731
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
732
|
+
const componentsMap = components.reduce(
|
|
733
|
+
(acc, component) => {
|
|
734
|
+
acc[component.uid] = component;
|
|
735
|
+
return acc;
|
|
736
|
+
},
|
|
737
|
+
{}
|
|
738
|
+
);
|
|
739
|
+
return componentsMap;
|
|
740
|
+
},
|
|
741
|
+
async delete(releaseId) {
|
|
742
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
743
|
+
where: { id: releaseId },
|
|
744
|
+
populate: {
|
|
745
|
+
actions: {
|
|
746
|
+
select: ["id"]
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
if (!release2) {
|
|
751
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
752
|
+
}
|
|
753
|
+
if (release2.releasedAt) {
|
|
754
|
+
throw new errors.ValidationError("Release already published");
|
|
755
|
+
}
|
|
756
|
+
await strapi2.db.transaction(async () => {
|
|
757
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
758
|
+
where: {
|
|
759
|
+
id: {
|
|
760
|
+
$in: release2.actions.map((action) => action.id)
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
765
|
+
where: {
|
|
766
|
+
id: releaseId
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
});
|
|
770
|
+
if (release2.scheduledAt) {
|
|
771
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
772
|
+
await schedulingService.cancel(release2.id);
|
|
773
|
+
}
|
|
774
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
775
|
+
return release2;
|
|
776
|
+
},
|
|
777
|
+
async publish(releaseId) {
|
|
778
|
+
const {
|
|
779
|
+
release: release2,
|
|
780
|
+
error
|
|
781
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
782
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
783
|
+
if (!lockedRelease) {
|
|
784
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
785
|
+
}
|
|
786
|
+
if (lockedRelease.releasedAt) {
|
|
787
|
+
throw new errors.ValidationError("Release already published");
|
|
788
|
+
}
|
|
789
|
+
if (lockedRelease.status === "failed") {
|
|
790
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
791
|
+
}
|
|
792
|
+
try {
|
|
793
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
794
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
795
|
+
await strapi2.db.transaction(
|
|
796
|
+
async () => Promise.all(
|
|
797
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
798
|
+
const contentType = contentTypeUid;
|
|
799
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
800
|
+
return Promise.all([
|
|
801
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
802
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
803
|
+
]);
|
|
804
|
+
})
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
808
|
+
where: {
|
|
809
|
+
id: releaseId
|
|
810
|
+
},
|
|
811
|
+
data: {
|
|
812
|
+
status: "done",
|
|
813
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
817
|
+
isPublished: true,
|
|
818
|
+
release: release22
|
|
819
|
+
});
|
|
820
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
821
|
+
return { release: release22, error: null };
|
|
822
|
+
} catch (error2) {
|
|
823
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
824
|
+
isPublished: false,
|
|
825
|
+
error: error2
|
|
826
|
+
});
|
|
827
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
828
|
+
status: "failed"
|
|
829
|
+
}).transacting(trx).execute();
|
|
830
|
+
return {
|
|
831
|
+
release: null,
|
|
832
|
+
error: error2
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
if (error instanceof Error) {
|
|
837
|
+
throw error;
|
|
838
|
+
}
|
|
839
|
+
return release2;
|
|
840
|
+
},
|
|
841
|
+
async updateReleaseStatus(releaseId) {
|
|
842
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
843
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
844
|
+
releaseActionService.countActions({
|
|
845
|
+
filters: {
|
|
846
|
+
release: releaseId
|
|
847
|
+
}
|
|
848
|
+
}),
|
|
849
|
+
releaseActionService.countActions({
|
|
850
|
+
filters: {
|
|
851
|
+
release: releaseId,
|
|
852
|
+
isEntryValid: false
|
|
853
|
+
}
|
|
854
|
+
})
|
|
855
|
+
]);
|
|
856
|
+
if (totalActions > 0) {
|
|
857
|
+
if (invalidActions > 0) {
|
|
858
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
859
|
+
where: {
|
|
860
|
+
id: releaseId
|
|
861
|
+
},
|
|
862
|
+
data: {
|
|
863
|
+
status: "blocked"
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
868
|
+
where: {
|
|
869
|
+
id: releaseId
|
|
870
|
+
},
|
|
871
|
+
data: {
|
|
872
|
+
status: "ready"
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
877
|
+
where: {
|
|
878
|
+
id: releaseId
|
|
879
|
+
},
|
|
880
|
+
data: {
|
|
881
|
+
status: "empty"
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
};
|
|
887
|
+
const getGroupName = (queryValue) => {
|
|
888
|
+
switch (queryValue) {
|
|
889
|
+
case "contentType":
|
|
890
|
+
return "contentType.displayName";
|
|
891
|
+
case "type":
|
|
892
|
+
return "type";
|
|
893
|
+
case "locale":
|
|
894
|
+
return _.getOr("No locale", "locale.name");
|
|
895
|
+
default:
|
|
896
|
+
return "contentType.displayName";
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
900
|
+
const getLocalesDataForActions = async () => {
|
|
901
|
+
if (!strapi2.plugin("i18n")) {
|
|
902
|
+
return {};
|
|
903
|
+
}
|
|
904
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
905
|
+
return allLocales.reduce((acc, locale) => {
|
|
906
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
907
|
+
return acc;
|
|
908
|
+
}, {});
|
|
909
|
+
};
|
|
910
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
911
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
912
|
+
const contentTypesData = {};
|
|
913
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
914
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
915
|
+
uid: contentTypeUid
|
|
916
|
+
});
|
|
917
|
+
contentTypesData[contentTypeUid] = {
|
|
918
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
919
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
return contentTypesData;
|
|
923
|
+
};
|
|
924
|
+
return {
|
|
925
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
926
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
782
927
|
strapi: strapi2
|
|
783
928
|
});
|
|
784
929
|
await Promise.all([
|
|
785
|
-
|
|
930
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
786
931
|
validateUniqueEntry(releaseId, action)
|
|
787
932
|
]);
|
|
933
|
+
const model = strapi2.contentType(action.contentType);
|
|
934
|
+
if (model.kind === "singleType") {
|
|
935
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
936
|
+
if (!document) {
|
|
937
|
+
throw new errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
938
|
+
}
|
|
939
|
+
action.entryDocumentId = document.documentId;
|
|
940
|
+
}
|
|
788
941
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
789
942
|
if (!release2) {
|
|
790
943
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -792,28 +945,30 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
792
945
|
if (release2.releasedAt) {
|
|
793
946
|
throw new errors.ValidationError("Release already published");
|
|
794
947
|
}
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
948
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
949
|
+
{
|
|
950
|
+
contentType: action.contentType,
|
|
951
|
+
documentId: action.entryDocumentId,
|
|
952
|
+
locale: action.locale
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
strapi: strapi2
|
|
956
|
+
}
|
|
957
|
+
) : true;
|
|
798
958
|
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
799
959
|
data: {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
isEntryValid,
|
|
804
|
-
entry: {
|
|
805
|
-
id: entry.id,
|
|
806
|
-
__type: entry.contentType,
|
|
807
|
-
__pivot: { field: "entry" }
|
|
808
|
-
},
|
|
809
|
-
release: releaseId
|
|
960
|
+
...action,
|
|
961
|
+
release: release2.id,
|
|
962
|
+
isEntryValid: actionStatus
|
|
810
963
|
},
|
|
811
|
-
populate: { release: { select: ["id"] }
|
|
964
|
+
populate: { release: { select: ["id"] } }
|
|
812
965
|
});
|
|
813
|
-
|
|
966
|
+
if (!disableUpdateReleaseStatus) {
|
|
967
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
968
|
+
}
|
|
814
969
|
return releaseAction2;
|
|
815
970
|
},
|
|
816
|
-
async
|
|
971
|
+
async findPage(releaseId, query) {
|
|
817
972
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
818
973
|
where: { id: releaseId },
|
|
819
974
|
select: ["id"]
|
|
@@ -822,21 +977,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
822
977
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
823
978
|
}
|
|
824
979
|
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
825
|
-
|
|
980
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
826
981
|
...dbQuery,
|
|
827
|
-
populate: {
|
|
828
|
-
entry: {
|
|
829
|
-
populate: "*"
|
|
830
|
-
}
|
|
831
|
-
},
|
|
832
982
|
where: {
|
|
833
983
|
release: releaseId
|
|
834
984
|
}
|
|
835
985
|
});
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
986
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
987
|
+
const actionsWithEntry = await async.map(actions, async (action) => {
|
|
988
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
989
|
+
const entry = await getEntry(
|
|
990
|
+
{
|
|
991
|
+
contentType: action.contentType,
|
|
992
|
+
documentId: action.entryDocumentId,
|
|
993
|
+
locale: action.locale,
|
|
994
|
+
populate,
|
|
995
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
996
|
+
},
|
|
997
|
+
{ strapi: strapi2 }
|
|
998
|
+
);
|
|
999
|
+
return {
|
|
1000
|
+
...action,
|
|
1001
|
+
entry,
|
|
1002
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1003
|
+
};
|
|
1004
|
+
});
|
|
1005
|
+
return {
|
|
1006
|
+
results: actionsWithEntry,
|
|
1007
|
+
pagination
|
|
1008
|
+
};
|
|
840
1009
|
},
|
|
841
1010
|
async groupActions(actions, groupBy) {
|
|
842
1011
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -845,8 +1014,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
845
1014
|
}
|
|
846
1015
|
return acc;
|
|
847
1016
|
}, []);
|
|
848
|
-
const allReleaseContentTypesDictionary = await
|
|
849
|
-
const allLocalesDictionary = await
|
|
1017
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1018
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
850
1019
|
const formattedData = actions.map((action) => {
|
|
851
1020
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
852
1021
|
return {
|
|
@@ -858,165 +1027,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
858
1027
|
uid: action.contentType
|
|
859
1028
|
}
|
|
860
1029
|
};
|
|
861
|
-
});
|
|
862
|
-
const groupName = getGroupName(groupBy);
|
|
863
|
-
return _.groupBy(groupName)(formattedData);
|
|
864
|
-
},
|
|
865
|
-
async getLocalesDataForActions() {
|
|
866
|
-
if (!strapi2.plugin("i18n")) {
|
|
867
|
-
return {};
|
|
868
|
-
}
|
|
869
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
870
|
-
return allLocales.reduce((acc, locale) => {
|
|
871
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
872
|
-
return acc;
|
|
873
|
-
}, {});
|
|
874
|
-
},
|
|
875
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
876
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
877
|
-
const contentTypesData = {};
|
|
878
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
879
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
880
|
-
uid: contentTypeUid
|
|
881
|
-
});
|
|
882
|
-
contentTypesData[contentTypeUid] = {
|
|
883
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
884
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
return contentTypesData;
|
|
888
|
-
},
|
|
889
|
-
getContentTypeModelsFromActions(actions) {
|
|
890
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
891
|
-
if (!acc.includes(action.contentType)) {
|
|
892
|
-
acc.push(action.contentType);
|
|
893
|
-
}
|
|
894
|
-
return acc;
|
|
895
|
-
}, []);
|
|
896
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
897
|
-
(acc, contentTypeUid) => {
|
|
898
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
899
|
-
return acc;
|
|
900
|
-
},
|
|
901
|
-
{}
|
|
902
|
-
);
|
|
903
|
-
return contentTypeModelsMap;
|
|
904
|
-
},
|
|
905
|
-
async getAllComponents() {
|
|
906
|
-
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
907
|
-
const components = await contentManagerComponentsService.findAllComponents();
|
|
908
|
-
const componentsMap = components.reduce(
|
|
909
|
-
(acc, component) => {
|
|
910
|
-
acc[component.uid] = component;
|
|
911
|
-
return acc;
|
|
912
|
-
},
|
|
913
|
-
{}
|
|
914
|
-
);
|
|
915
|
-
return componentsMap;
|
|
916
|
-
},
|
|
917
|
-
async delete(releaseId) {
|
|
918
|
-
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
919
|
-
where: { id: releaseId },
|
|
920
|
-
populate: {
|
|
921
|
-
actions: {
|
|
922
|
-
select: ["id"]
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
});
|
|
926
|
-
if (!release2) {
|
|
927
|
-
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
928
|
-
}
|
|
929
|
-
if (release2.releasedAt) {
|
|
930
|
-
throw new errors.ValidationError("Release already published");
|
|
931
|
-
}
|
|
932
|
-
await strapi2.db.transaction(async () => {
|
|
933
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
934
|
-
where: {
|
|
935
|
-
id: {
|
|
936
|
-
$in: release2.actions.map((action) => action.id)
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
941
|
-
where: {
|
|
942
|
-
id: releaseId
|
|
943
|
-
}
|
|
944
|
-
});
|
|
945
|
-
});
|
|
946
|
-
if (release2.scheduledAt) {
|
|
947
|
-
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
948
|
-
await schedulingService.cancel(release2.id);
|
|
949
|
-
}
|
|
950
|
-
strapi2.telemetry.send("didDeleteContentRelease");
|
|
951
|
-
return release2;
|
|
1030
|
+
});
|
|
1031
|
+
const groupName = getGroupName(groupBy);
|
|
1032
|
+
return _.groupBy(groupName)(formattedData);
|
|
952
1033
|
},
|
|
953
|
-
async
|
|
954
|
-
const {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
958
|
-
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
959
|
-
if (!lockedRelease) {
|
|
960
|
-
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
961
|
-
}
|
|
962
|
-
if (lockedRelease.releasedAt) {
|
|
963
|
-
throw new errors.ValidationError("Release already published");
|
|
964
|
-
}
|
|
965
|
-
if (lockedRelease.status === "failed") {
|
|
966
|
-
throw new errors.ValidationError("Release failed to publish");
|
|
1034
|
+
async getContentTypeModelsFromActions(actions) {
|
|
1035
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1036
|
+
if (!acc.includes(action.contentType)) {
|
|
1037
|
+
acc.push(action.contentType);
|
|
967
1038
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
await publishCollectionTypeAction(
|
|
978
|
-
uid,
|
|
979
|
-
collectionTypeActions[uid].entriesToPublishIds,
|
|
980
|
-
collectionTypeActions[uid].entriesToUnpublishIds
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
});
|
|
984
|
-
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
985
|
-
where: {
|
|
986
|
-
id: releaseId
|
|
987
|
-
},
|
|
988
|
-
data: {
|
|
989
|
-
status: "done",
|
|
990
|
-
releasedAt: /* @__PURE__ */ new Date()
|
|
991
|
-
}
|
|
992
|
-
});
|
|
993
|
-
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
994
|
-
isPublished: true,
|
|
995
|
-
release: release22
|
|
996
|
-
});
|
|
997
|
-
strapi2.telemetry.send("didPublishContentRelease");
|
|
998
|
-
return { release: release22, error: null };
|
|
999
|
-
} catch (error2) {
|
|
1000
|
-
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
1001
|
-
isPublished: false,
|
|
1002
|
-
error: error2
|
|
1039
|
+
return acc;
|
|
1040
|
+
}, []);
|
|
1041
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
1042
|
+
const contentTypeModelsMap = await async.reduce(contentTypeUids)(
|
|
1043
|
+
async (accPromise, contentTypeUid) => {
|
|
1044
|
+
const acc = await accPromise;
|
|
1045
|
+
const contentTypeModel = strapi2.getModel(contentTypeUid);
|
|
1046
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
1047
|
+
populate: "stageRequiredToPublish"
|
|
1003
1048
|
});
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
release: null,
|
|
1009
|
-
error: error2
|
|
1049
|
+
acc[contentTypeUid] = {
|
|
1050
|
+
...contentTypeModel,
|
|
1051
|
+
hasReviewWorkflow: !!workflow,
|
|
1052
|
+
stageRequiredToPublish: workflow?.stageRequiredToPublish
|
|
1010
1053
|
};
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
return release2;
|
|
1054
|
+
return acc;
|
|
1055
|
+
},
|
|
1056
|
+
{}
|
|
1057
|
+
);
|
|
1058
|
+
return contentTypeModelsMap;
|
|
1017
1059
|
},
|
|
1018
|
-
async
|
|
1019
|
-
const
|
|
1060
|
+
async countActions(query) {
|
|
1061
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1062
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1063
|
+
},
|
|
1064
|
+
async update(actionId, releaseId, update) {
|
|
1065
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1020
1066
|
where: {
|
|
1021
1067
|
id: actionId,
|
|
1022
1068
|
release: {
|
|
@@ -1025,17 +1071,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1025
1071
|
$null: true
|
|
1026
1072
|
}
|
|
1027
1073
|
}
|
|
1028
|
-
}
|
|
1029
|
-
data: update
|
|
1074
|
+
}
|
|
1030
1075
|
});
|
|
1031
|
-
if (!
|
|
1076
|
+
if (!action) {
|
|
1032
1077
|
throw new errors.NotFoundError(
|
|
1033
1078
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1034
1079
|
);
|
|
1035
1080
|
}
|
|
1081
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1082
|
+
{
|
|
1083
|
+
contentType: action.contentType,
|
|
1084
|
+
documentId: action.entryDocumentId,
|
|
1085
|
+
locale: action.locale
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
strapi: strapi2
|
|
1089
|
+
}
|
|
1090
|
+
) : true;
|
|
1091
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1092
|
+
where: {
|
|
1093
|
+
id: actionId,
|
|
1094
|
+
release: {
|
|
1095
|
+
id: releaseId,
|
|
1096
|
+
releasedAt: {
|
|
1097
|
+
$null: true
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
data: {
|
|
1102
|
+
...update,
|
|
1103
|
+
isEntryValid: actionStatus
|
|
1104
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1036
1107
|
return updatedAction;
|
|
1037
1108
|
},
|
|
1038
|
-
async
|
|
1109
|
+
async delete(actionId, releaseId) {
|
|
1039
1110
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1040
1111
|
where: {
|
|
1041
1112
|
id: actionId,
|
|
@@ -1052,51 +1123,56 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1052
1123
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1053
1124
|
);
|
|
1054
1125
|
}
|
|
1055
|
-
|
|
1126
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1056
1127
|
return deletedAction;
|
|
1057
1128
|
},
|
|
1058
|
-
async
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
1070
|
-
})
|
|
1071
|
-
]);
|
|
1072
|
-
if (totalActions > 0) {
|
|
1073
|
-
if (invalidActions > 0) {
|
|
1074
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1075
|
-
where: {
|
|
1076
|
-
id: releaseId
|
|
1077
|
-
},
|
|
1078
|
-
data: {
|
|
1079
|
-
status: "blocked"
|
|
1129
|
+
async validateActionsByContentTypes(contentTypeUids) {
|
|
1130
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
1131
|
+
where: {
|
|
1132
|
+
contentType: {
|
|
1133
|
+
$in: contentTypeUids
|
|
1134
|
+
},
|
|
1135
|
+
// We only want to validate actions that are going to be published
|
|
1136
|
+
type: "publish",
|
|
1137
|
+
release: {
|
|
1138
|
+
releasedAt: {
|
|
1139
|
+
$null: true
|
|
1080
1140
|
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1141
|
+
}
|
|
1142
|
+
},
|
|
1143
|
+
populate: { release: true }
|
|
1144
|
+
});
|
|
1145
|
+
const releasesUpdated = [];
|
|
1146
|
+
await async.map(actions, async (action) => {
|
|
1147
|
+
const isValid = await getDraftEntryValidStatus(
|
|
1148
|
+
{
|
|
1149
|
+
contentType: action.contentType,
|
|
1150
|
+
documentId: action.entryDocumentId,
|
|
1151
|
+
locale: action.locale
|
|
1152
|
+
},
|
|
1153
|
+
{ strapi: strapi2 }
|
|
1154
|
+
);
|
|
1155
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1084
1156
|
where: {
|
|
1085
|
-
id:
|
|
1157
|
+
id: action.id
|
|
1086
1158
|
},
|
|
1087
1159
|
data: {
|
|
1088
|
-
|
|
1160
|
+
isEntryValid: isValid
|
|
1089
1161
|
}
|
|
1090
1162
|
});
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
where: {
|
|
1094
|
-
id: releaseId
|
|
1095
|
-
},
|
|
1096
|
-
data: {
|
|
1097
|
-
status: "empty"
|
|
1163
|
+
if (!releasesUpdated.includes(action.release.id)) {
|
|
1164
|
+
releasesUpdated.push(action.release.id);
|
|
1098
1165
|
}
|
|
1166
|
+
return {
|
|
1167
|
+
id: action.id,
|
|
1168
|
+
isEntryValid: isValid
|
|
1169
|
+
};
|
|
1099
1170
|
});
|
|
1171
|
+
if (releasesUpdated.length > 0) {
|
|
1172
|
+
await async.map(releasesUpdated, async (releaseId) => {
|
|
1173
|
+
await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1100
1176
|
}
|
|
1101
1177
|
};
|
|
1102
1178
|
};
|
|
@@ -1112,30 +1188,35 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1112
1188
|
where: {
|
|
1113
1189
|
id: releaseId
|
|
1114
1190
|
},
|
|
1115
|
-
populate: {
|
|
1191
|
+
populate: {
|
|
1192
|
+
actions: true
|
|
1193
|
+
}
|
|
1116
1194
|
});
|
|
1117
1195
|
if (!release2) {
|
|
1118
1196
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1119
1197
|
}
|
|
1120
1198
|
const isEntryInRelease = release2.actions.some(
|
|
1121
|
-
(action) =>
|
|
1199
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1122
1200
|
);
|
|
1123
1201
|
if (isEntryInRelease) {
|
|
1124
1202
|
throw new AlreadyOnReleaseError(
|
|
1125
|
-
`Entry with
|
|
1203
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1126
1204
|
);
|
|
1127
1205
|
}
|
|
1128
1206
|
},
|
|
1129
|
-
|
|
1207
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1130
1208
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1131
1209
|
if (!contentType) {
|
|
1132
1210
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1133
1211
|
}
|
|
1134
|
-
if (!contentType
|
|
1212
|
+
if (!contentTypes$1.hasDraftAndPublish(contentType)) {
|
|
1135
1213
|
throw new errors.ValidationError(
|
|
1136
1214
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1137
1215
|
);
|
|
1138
1216
|
}
|
|
1217
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1218
|
+
throw new errors.ValidationError("Document id is required for collection type");
|
|
1219
|
+
}
|
|
1139
1220
|
},
|
|
1140
1221
|
async validatePendingReleasesLimit() {
|
|
1141
1222
|
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
@@ -1224,78 +1305,165 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1224
1305
|
}
|
|
1225
1306
|
};
|
|
1226
1307
|
};
|
|
1308
|
+
const DEFAULT_SETTINGS = {
|
|
1309
|
+
defaultTimezone: null
|
|
1310
|
+
};
|
|
1311
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1312
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1313
|
+
return {
|
|
1314
|
+
async update({ settings: settings2 }) {
|
|
1315
|
+
const store = await getStore();
|
|
1316
|
+
store.set({ key: "settings", value: settings2 });
|
|
1317
|
+
return settings2;
|
|
1318
|
+
},
|
|
1319
|
+
async find() {
|
|
1320
|
+
const store = await getStore();
|
|
1321
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1322
|
+
return {
|
|
1323
|
+
...DEFAULT_SETTINGS,
|
|
1324
|
+
...settings2 || {}
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
};
|
|
1227
1329
|
const services = {
|
|
1228
1330
|
release: createReleaseService,
|
|
1331
|
+
"release-action": createReleaseActionService,
|
|
1229
1332
|
"release-validation": createReleaseValidationService,
|
|
1230
|
-
scheduling: createSchedulingService
|
|
1333
|
+
scheduling: createSchedulingService,
|
|
1334
|
+
settings: createSettingsService
|
|
1231
1335
|
};
|
|
1232
|
-
const RELEASE_SCHEMA = yup.object().shape({
|
|
1233
|
-
name: yup.string().trim().required(),
|
|
1234
|
-
scheduledAt: yup.string().nullable(),
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
otherwise: yup.string().nullable()
|
|
1240
|
-
}),
|
|
1241
|
-
timezone: yup.string().when("isScheduled", {
|
|
1242
|
-
is: true,
|
|
1243
|
-
then: yup.string().required().nullable(),
|
|
1244
|
-
otherwise: yup.string().nullable()
|
|
1245
|
-
}),
|
|
1246
|
-
date: yup.string().when("isScheduled", {
|
|
1247
|
-
is: true,
|
|
1248
|
-
then: yup.string().required().nullable(),
|
|
1249
|
-
otherwise: yup.string().nullable()
|
|
1336
|
+
const RELEASE_SCHEMA = yup$1.object().shape({
|
|
1337
|
+
name: yup$1.string().trim().required(),
|
|
1338
|
+
scheduledAt: yup$1.string().nullable(),
|
|
1339
|
+
timezone: yup$1.string().when("scheduledAt", {
|
|
1340
|
+
is: (value) => value !== null && value !== void 0,
|
|
1341
|
+
then: yup$1.string().required(),
|
|
1342
|
+
otherwise: yup$1.string().nullable()
|
|
1250
1343
|
})
|
|
1251
1344
|
}).required().noUnknown();
|
|
1345
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = yup$1.object().shape({
|
|
1346
|
+
contentType: yup$1.string().required(),
|
|
1347
|
+
entryDocumentId: yup$1.string().nullable(),
|
|
1348
|
+
hasEntryAttached: yup$1.string().nullable(),
|
|
1349
|
+
locale: yup$1.string().nullable()
|
|
1350
|
+
}).required().noUnknown();
|
|
1252
1351
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
1352
|
+
const validatefindByDocumentAttachedParams = validateYupSchema(
|
|
1353
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1354
|
+
);
|
|
1253
1355
|
const releaseController = {
|
|
1254
|
-
|
|
1356
|
+
/**
|
|
1357
|
+
* Find releases based on documents attached or not to the release.
|
|
1358
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1359
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1360
|
+
*/
|
|
1361
|
+
async findByDocumentAttached(ctx) {
|
|
1255
1362
|
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1256
1363
|
ability: ctx.state.userAbility,
|
|
1257
1364
|
model: RELEASE_MODEL_UID
|
|
1258
1365
|
});
|
|
1259
1366
|
await permissionsManager.validateQuery(ctx.query);
|
|
1260
1367
|
const releaseService = getService("release", { strapi });
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1368
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1369
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1370
|
+
const model = strapi.getModel(query.contentType);
|
|
1371
|
+
if (model.kind && model.kind === "singleType") {
|
|
1372
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1373
|
+
if (!document) {
|
|
1374
|
+
throw new errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1375
|
+
}
|
|
1376
|
+
query.entryDocumentId = document.documentId;
|
|
1377
|
+
}
|
|
1378
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1379
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1380
|
+
if (isEntryAttached) {
|
|
1381
|
+
const releases = await releaseService.findMany({
|
|
1382
|
+
where: {
|
|
1383
|
+
releasedAt: null,
|
|
1384
|
+
actions: {
|
|
1385
|
+
contentType,
|
|
1386
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1387
|
+
locale: locale ?? null
|
|
1388
|
+
}
|
|
1389
|
+
},
|
|
1390
|
+
populate: {
|
|
1276
1391
|
actions: {
|
|
1277
|
-
|
|
1278
|
-
|
|
1392
|
+
fields: ["type"],
|
|
1393
|
+
filters: {
|
|
1394
|
+
contentType,
|
|
1395
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1396
|
+
locale: locale ?? null
|
|
1279
1397
|
}
|
|
1280
1398
|
}
|
|
1281
|
-
}
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
ctx.body = { data: releases };
|
|
1402
|
+
} else {
|
|
1403
|
+
const relatedReleases = await releaseService.findMany({
|
|
1404
|
+
where: {
|
|
1405
|
+
releasedAt: null,
|
|
1406
|
+
actions: {
|
|
1407
|
+
contentType,
|
|
1408
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1409
|
+
locale: locale ?? null
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1282
1412
|
});
|
|
1283
|
-
const
|
|
1413
|
+
const releases = await releaseService.findMany({
|
|
1284
1414
|
where: {
|
|
1415
|
+
$or: [
|
|
1416
|
+
{
|
|
1417
|
+
id: {
|
|
1418
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1419
|
+
}
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
actions: null
|
|
1423
|
+
}
|
|
1424
|
+
],
|
|
1285
1425
|
releasedAt: null
|
|
1286
1426
|
}
|
|
1287
1427
|
});
|
|
1288
|
-
ctx.body = { data
|
|
1428
|
+
ctx.body = { data: releases };
|
|
1289
1429
|
}
|
|
1290
1430
|
},
|
|
1431
|
+
async findPage(ctx) {
|
|
1432
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1433
|
+
ability: ctx.state.userAbility,
|
|
1434
|
+
model: RELEASE_MODEL_UID
|
|
1435
|
+
});
|
|
1436
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1437
|
+
const releaseService = getService("release", { strapi });
|
|
1438
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1439
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1440
|
+
const data = results.map((release2) => {
|
|
1441
|
+
const { actions, ...releaseData } = release2;
|
|
1442
|
+
return {
|
|
1443
|
+
...releaseData,
|
|
1444
|
+
actions: {
|
|
1445
|
+
meta: {
|
|
1446
|
+
count: actions.count
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
});
|
|
1451
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1452
|
+
where: {
|
|
1453
|
+
releasedAt: null
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1457
|
+
},
|
|
1291
1458
|
async findOne(ctx) {
|
|
1292
1459
|
const id = ctx.params.id;
|
|
1293
1460
|
const releaseService = getService("release", { strapi });
|
|
1461
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1294
1462
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1295
1463
|
if (!release2) {
|
|
1296
1464
|
throw new errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1297
1465
|
}
|
|
1298
|
-
const count = await
|
|
1466
|
+
const count = await releaseActionService.countActions({
|
|
1299
1467
|
filters: {
|
|
1300
1468
|
release: id
|
|
1301
1469
|
}
|
|
@@ -1315,28 +1483,43 @@ const releaseController = {
|
|
|
1315
1483
|
ctx.body = { data };
|
|
1316
1484
|
},
|
|
1317
1485
|
async mapEntriesToReleases(ctx) {
|
|
1318
|
-
const { contentTypeUid,
|
|
1319
|
-
if (!contentTypeUid || !
|
|
1486
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1487
|
+
if (!contentTypeUid || !documentIds) {
|
|
1320
1488
|
throw new errors.ValidationError("Missing required query parameters");
|
|
1321
1489
|
}
|
|
1322
1490
|
const releaseService = getService("release", { strapi });
|
|
1323
|
-
const releasesWithActions = await releaseService.
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1491
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1492
|
+
where: {
|
|
1493
|
+
releasedAt: null,
|
|
1494
|
+
actions: {
|
|
1495
|
+
contentType: contentTypeUid,
|
|
1496
|
+
entryDocumentId: {
|
|
1497
|
+
$in: documentIds
|
|
1498
|
+
},
|
|
1499
|
+
locale
|
|
1500
|
+
}
|
|
1501
|
+
},
|
|
1502
|
+
populate: {
|
|
1503
|
+
actions: true
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1327
1506
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1328
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1329
1507
|
(acc, release2) => {
|
|
1330
1508
|
release2.actions.forEach((action) => {
|
|
1331
|
-
if (
|
|
1332
|
-
|
|
1509
|
+
if (action.contentType !== contentTypeUid) {
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
if (locale && action.locale !== locale) {
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
if (!acc[action.entryDocumentId]) {
|
|
1516
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1333
1517
|
} else {
|
|
1334
|
-
acc[action.
|
|
1518
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1335
1519
|
}
|
|
1336
1520
|
});
|
|
1337
1521
|
return acc;
|
|
1338
1522
|
},
|
|
1339
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1340
1523
|
{}
|
|
1341
1524
|
);
|
|
1342
1525
|
ctx.body = {
|
|
@@ -1381,18 +1564,18 @@ const releaseController = {
|
|
|
1381
1564
|
};
|
|
1382
1565
|
},
|
|
1383
1566
|
async publish(ctx) {
|
|
1384
|
-
const user = ctx.state.user;
|
|
1385
1567
|
const id = ctx.params.id;
|
|
1386
1568
|
const releaseService = getService("release", { strapi });
|
|
1387
|
-
const
|
|
1569
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1570
|
+
const release2 = await releaseService.publish(id);
|
|
1388
1571
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1389
|
-
|
|
1572
|
+
releaseActionService.countActions({
|
|
1390
1573
|
filters: {
|
|
1391
1574
|
release: id,
|
|
1392
1575
|
type: "publish"
|
|
1393
1576
|
}
|
|
1394
1577
|
}),
|
|
1395
|
-
|
|
1578
|
+
releaseActionService.countActions({
|
|
1396
1579
|
filters: {
|
|
1397
1580
|
release: id,
|
|
1398
1581
|
type: "unpublish"
|
|
@@ -1410,24 +1593,27 @@ const releaseController = {
|
|
|
1410
1593
|
}
|
|
1411
1594
|
};
|
|
1412
1595
|
const RELEASE_ACTION_SCHEMA = yup$1.object().shape({
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
}).required(),
|
|
1596
|
+
contentType: yup$1.string().required(),
|
|
1597
|
+
entryDocumentId: yup$1.strapiID(),
|
|
1598
|
+
locale: yup$1.string(),
|
|
1417
1599
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1418
1600
|
});
|
|
1419
1601
|
const RELEASE_ACTION_UPDATE_SCHEMA = yup$1.object().shape({
|
|
1420
1602
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1421
1603
|
});
|
|
1604
|
+
const FIND_MANY_ACTIONS_PARAMS = yup$1.object().shape({
|
|
1605
|
+
groupBy: yup$1.string().oneOf(["action", "contentType", "locale"])
|
|
1606
|
+
});
|
|
1422
1607
|
const validateReleaseAction = validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1423
1608
|
const validateReleaseActionUpdateSchema = validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1609
|
+
const validateFindManyActionsParams = validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1424
1610
|
const releaseActionController = {
|
|
1425
1611
|
async create(ctx) {
|
|
1426
1612
|
const releaseId = ctx.params.releaseId;
|
|
1427
1613
|
const releaseActionArgs = ctx.request.body;
|
|
1428
1614
|
await validateReleaseAction(releaseActionArgs);
|
|
1429
|
-
const
|
|
1430
|
-
const releaseAction2 = await
|
|
1615
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1616
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1431
1617
|
ctx.created({
|
|
1432
1618
|
data: releaseAction2
|
|
1433
1619
|
});
|
|
@@ -1438,12 +1624,15 @@ const releaseActionController = {
|
|
|
1438
1624
|
await Promise.all(
|
|
1439
1625
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1440
1626
|
);
|
|
1627
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1441
1628
|
const releaseService = getService("release", { strapi });
|
|
1442
1629
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1443
1630
|
const releaseActions2 = await Promise.all(
|
|
1444
1631
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1445
1632
|
try {
|
|
1446
|
-
const action = await
|
|
1633
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1634
|
+
disableUpdateReleaseStatus: true
|
|
1635
|
+
});
|
|
1447
1636
|
return action;
|
|
1448
1637
|
} catch (error) {
|
|
1449
1638
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1456,6 +1645,9 @@ const releaseActionController = {
|
|
|
1456
1645
|
return releaseActions2;
|
|
1457
1646
|
});
|
|
1458
1647
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1648
|
+
if (newReleaseActions.length > 0) {
|
|
1649
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1650
|
+
}
|
|
1459
1651
|
ctx.created({
|
|
1460
1652
|
data: newReleaseActions,
|
|
1461
1653
|
meta: {
|
|
@@ -1470,10 +1662,17 @@ const releaseActionController = {
|
|
|
1470
1662
|
ability: ctx.state.userAbility,
|
|
1471
1663
|
model: RELEASE_ACTION_MODEL_UID
|
|
1472
1664
|
});
|
|
1665
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1666
|
+
if (ctx.query.groupBy) {
|
|
1667
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1668
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1672
|
+
delete ctx.query.groupBy;
|
|
1473
1673
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1474
|
-
const
|
|
1475
|
-
const { results, pagination } = await
|
|
1476
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1674
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1675
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1477
1676
|
...query
|
|
1478
1677
|
});
|
|
1479
1678
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
@@ -1489,10 +1688,11 @@ const releaseActionController = {
|
|
|
1489
1688
|
}, {});
|
|
1490
1689
|
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1491
1690
|
...action,
|
|
1492
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1691
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1493
1692
|
}));
|
|
1494
|
-
const groupedData = await
|
|
1495
|
-
const contentTypes2 =
|
|
1693
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1694
|
+
const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
|
|
1695
|
+
const releaseService = getService("release", { strapi });
|
|
1496
1696
|
const components = await releaseService.getAllComponents();
|
|
1497
1697
|
ctx.body = {
|
|
1498
1698
|
data: groupedData,
|
|
@@ -1508,8 +1708,8 @@ const releaseActionController = {
|
|
|
1508
1708
|
const releaseId = ctx.params.releaseId;
|
|
1509
1709
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1510
1710
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1511
|
-
const
|
|
1512
|
-
const updatedAction = await
|
|
1711
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1712
|
+
const updatedAction = await releaseActionService.update(
|
|
1513
1713
|
actionId,
|
|
1514
1714
|
releaseId,
|
|
1515
1715
|
releaseActionUpdateArgs
|
|
@@ -1521,14 +1721,36 @@ const releaseActionController = {
|
|
|
1521
1721
|
async delete(ctx) {
|
|
1522
1722
|
const actionId = ctx.params.actionId;
|
|
1523
1723
|
const releaseId = ctx.params.releaseId;
|
|
1524
|
-
const
|
|
1525
|
-
const deletedReleaseAction = await
|
|
1724
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1725
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1526
1726
|
ctx.body = {
|
|
1527
1727
|
data: deletedReleaseAction
|
|
1528
1728
|
};
|
|
1529
1729
|
}
|
|
1530
1730
|
};
|
|
1531
|
-
const
|
|
1731
|
+
const SETTINGS_SCHEMA = yup.object().shape({
|
|
1732
|
+
defaultTimezone: yup.string().nullable().default(null)
|
|
1733
|
+
}).required().noUnknown();
|
|
1734
|
+
const validateSettings = validateYupSchema(SETTINGS_SCHEMA);
|
|
1735
|
+
const settingsController = {
|
|
1736
|
+
async find(ctx) {
|
|
1737
|
+
const settingsService = getService("settings", { strapi });
|
|
1738
|
+
const settings2 = await settingsService.find();
|
|
1739
|
+
ctx.body = { data: settings2 };
|
|
1740
|
+
},
|
|
1741
|
+
async update(ctx) {
|
|
1742
|
+
const settingsBody = ctx.request.body;
|
|
1743
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1744
|
+
const settingsService = getService("settings", { strapi });
|
|
1745
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1746
|
+
ctx.body = { data: updatedSettings };
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
const controllers = {
|
|
1750
|
+
release: releaseController,
|
|
1751
|
+
"release-action": releaseActionController,
|
|
1752
|
+
settings: settingsController
|
|
1753
|
+
};
|
|
1532
1754
|
const release = {
|
|
1533
1755
|
type: "admin",
|
|
1534
1756
|
routes: [
|
|
@@ -1548,6 +1770,22 @@ const release = {
|
|
|
1548
1770
|
]
|
|
1549
1771
|
}
|
|
1550
1772
|
},
|
|
1773
|
+
{
|
|
1774
|
+
method: "GET",
|
|
1775
|
+
path: "/getByDocumentAttached",
|
|
1776
|
+
handler: "release.findByDocumentAttached",
|
|
1777
|
+
config: {
|
|
1778
|
+
policies: [
|
|
1779
|
+
"admin::isAuthenticatedAdmin",
|
|
1780
|
+
{
|
|
1781
|
+
name: "admin::hasPermissions",
|
|
1782
|
+
config: {
|
|
1783
|
+
actions: ["plugin::content-releases.read"]
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
]
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1551
1789
|
{
|
|
1552
1790
|
method: "POST",
|
|
1553
1791
|
path: "/",
|
|
@@ -1567,7 +1805,7 @@ const release = {
|
|
|
1567
1805
|
{
|
|
1568
1806
|
method: "GET",
|
|
1569
1807
|
path: "/",
|
|
1570
|
-
handler: "release.
|
|
1808
|
+
handler: "release.findPage",
|
|
1571
1809
|
config: {
|
|
1572
1810
|
policies: [
|
|
1573
1811
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1731,7 +1969,45 @@ const releaseAction = {
|
|
|
1731
1969
|
}
|
|
1732
1970
|
]
|
|
1733
1971
|
};
|
|
1972
|
+
const settings = {
|
|
1973
|
+
type: "admin",
|
|
1974
|
+
routes: [
|
|
1975
|
+
{
|
|
1976
|
+
method: "GET",
|
|
1977
|
+
path: "/settings",
|
|
1978
|
+
handler: "settings.find",
|
|
1979
|
+
config: {
|
|
1980
|
+
policies: [
|
|
1981
|
+
"admin::isAuthenticatedAdmin",
|
|
1982
|
+
{
|
|
1983
|
+
name: "admin::hasPermissions",
|
|
1984
|
+
config: {
|
|
1985
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
]
|
|
1989
|
+
}
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
method: "PUT",
|
|
1993
|
+
path: "/settings",
|
|
1994
|
+
handler: "settings.update",
|
|
1995
|
+
config: {
|
|
1996
|
+
policies: [
|
|
1997
|
+
"admin::isAuthenticatedAdmin",
|
|
1998
|
+
{
|
|
1999
|
+
name: "admin::hasPermissions",
|
|
2000
|
+
config: {
|
|
2001
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
]
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
]
|
|
2008
|
+
};
|
|
1734
2009
|
const routes = {
|
|
2010
|
+
settings,
|
|
1735
2011
|
release,
|
|
1736
2012
|
"release-action": releaseAction
|
|
1737
2013
|
};
|