@strapi/content-releases 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.eba25ec571b091c6bde1104eb6c753debdf15462
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-FQyYFBJT.mjs} +642 -426
- package/dist/_chunks/App-FQyYFBJT.mjs.map +1 -0
- package/dist/_chunks/{App-CXRpb2hi.js → App-lx4Ucy9W.js} +680 -466
- package/dist/_chunks/App-lx4Ucy9W.js.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-DqBxvJ9i.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-DqBxvJ9i.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-T5VEAV03.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-T5VEAV03.js.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-CK9G80CL.mjs} +740 -600
- package/dist/_chunks/index-CK9G80CL.mjs.map +1 -0
- package/dist/_chunks/{index-B6-lic1Q.js → index-Cl3tM1YW.js} +731 -593
- package/dist/_chunks/index-Cl3tM1YW.js.map +1 -0
- package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
- package/dist/_chunks/schemas-BE1LxE9J.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 +888 -612
- 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 +23 -22
- package/dist/_chunks/App-BsUSTHVD.mjs.map +0 -1
- package/dist/_chunks/App-CXRpb2hi.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
|
@@ -71,6 +71,23 @@ const ACTIONS = [
|
|
|
71
71
|
displayName: "Add an entry to a release",
|
|
72
72
|
uid: "create-action",
|
|
73
73
|
pluginName: "content-releases"
|
|
74
|
+
},
|
|
75
|
+
// Settings
|
|
76
|
+
{
|
|
77
|
+
uid: "settings.read",
|
|
78
|
+
section: "settings",
|
|
79
|
+
displayName: "Read",
|
|
80
|
+
category: "content releases",
|
|
81
|
+
subCategory: "options",
|
|
82
|
+
pluginName: "content-releases"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
uid: "settings.update",
|
|
86
|
+
section: "settings",
|
|
87
|
+
displayName: "Edit",
|
|
88
|
+
category: "content releases",
|
|
89
|
+
subCategory: "options",
|
|
90
|
+
pluginName: "content-releases"
|
|
74
91
|
}
|
|
75
92
|
];
|
|
76
93
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
@@ -79,16 +96,13 @@ const ALLOWED_WEBHOOK_EVENTS = {
|
|
|
79
96
|
const getService = (name, { strapi: strapi2 }) => {
|
|
80
97
|
return strapi2.plugin("content-releases").service(name);
|
|
81
98
|
};
|
|
82
|
-
const
|
|
99
|
+
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi: strapi2 }) => {
|
|
83
100
|
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;
|
|
101
|
+
const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();
|
|
102
|
+
const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi: strapi2 });
|
|
103
|
+
return isEntryValid(contentType, entry, { strapi: strapi2 });
|
|
90
104
|
};
|
|
91
|
-
const
|
|
105
|
+
const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
92
106
|
try {
|
|
93
107
|
await strapi2.entityValidator.validateEntityCreation(
|
|
94
108
|
strapi2.getModel(contentTypeUid),
|
|
@@ -97,11 +111,54 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) =
|
|
|
97
111
|
// @ts-expect-error - FIXME: entity here is unnecessary
|
|
98
112
|
entry
|
|
99
113
|
);
|
|
114
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
115
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
116
|
+
populate: "stageRequiredToPublish"
|
|
117
|
+
});
|
|
118
|
+
if (workflow?.stageRequiredToPublish) {
|
|
119
|
+
return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;
|
|
120
|
+
}
|
|
100
121
|
return true;
|
|
101
122
|
} catch {
|
|
102
123
|
return false;
|
|
103
124
|
}
|
|
104
125
|
};
|
|
126
|
+
const getEntry = async ({
|
|
127
|
+
contentType,
|
|
128
|
+
documentId,
|
|
129
|
+
locale,
|
|
130
|
+
populate,
|
|
131
|
+
status = "draft"
|
|
132
|
+
}, { strapi: strapi2 }) => {
|
|
133
|
+
if (documentId) {
|
|
134
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
135
|
+
if (status === "published" && !entry) {
|
|
136
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
137
|
+
}
|
|
138
|
+
return entry;
|
|
139
|
+
}
|
|
140
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
141
|
+
};
|
|
142
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
143
|
+
if (entry.publishedAt) {
|
|
144
|
+
return "published";
|
|
145
|
+
}
|
|
146
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
147
|
+
documentId: entry.documentId,
|
|
148
|
+
locale: entry.locale,
|
|
149
|
+
status: "published",
|
|
150
|
+
fields: ["updatedAt"]
|
|
151
|
+
});
|
|
152
|
+
if (!publishedEntry) {
|
|
153
|
+
return "draft";
|
|
154
|
+
}
|
|
155
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
156
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
157
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
158
|
+
return "modified";
|
|
159
|
+
}
|
|
160
|
+
return "published";
|
|
161
|
+
};
|
|
105
162
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
106
163
|
oldContentTypes,
|
|
107
164
|
contentTypes: contentTypes2
|
|
@@ -147,20 +204,22 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
147
204
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
148
205
|
for (const action of notValidatedActions) {
|
|
149
206
|
if (action.entry) {
|
|
150
|
-
const
|
|
151
|
-
|
|
207
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
208
|
+
{
|
|
209
|
+
contentType: action.contentType,
|
|
210
|
+
documentId: action.entryDocumentId,
|
|
211
|
+
locale: action.locale
|
|
212
|
+
},
|
|
213
|
+
{ strapi }
|
|
214
|
+
);
|
|
215
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
216
|
+
where: {
|
|
217
|
+
id: action.id
|
|
218
|
+
},
|
|
219
|
+
data: {
|
|
220
|
+
isEntryValid: isEntryValid2
|
|
221
|
+
}
|
|
152
222
|
});
|
|
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
223
|
}
|
|
165
224
|
}
|
|
166
225
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -204,24 +263,24 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
204
263
|
}
|
|
205
264
|
});
|
|
206
265
|
await utils.async.map(actions, async (action) => {
|
|
207
|
-
if (action.entry && action.release) {
|
|
208
|
-
const
|
|
209
|
-
|
|
266
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
267
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
268
|
+
{
|
|
269
|
+
contentType: contentTypeUID,
|
|
270
|
+
documentId: action.entryDocumentId,
|
|
271
|
+
locale: action.locale
|
|
272
|
+
},
|
|
273
|
+
{ strapi }
|
|
274
|
+
);
|
|
275
|
+
releasesAffected.add(action.release.id);
|
|
276
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
277
|
+
where: {
|
|
278
|
+
id: action.id
|
|
279
|
+
},
|
|
280
|
+
data: {
|
|
281
|
+
isEntryValid: isEntryValid2
|
|
282
|
+
}
|
|
210
283
|
});
|
|
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
284
|
}
|
|
226
285
|
});
|
|
227
286
|
}
|
|
@@ -278,9 +337,42 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
278
337
|
}
|
|
279
338
|
}
|
|
280
339
|
}
|
|
340
|
+
const addEntryDocumentToReleaseActions = {
|
|
341
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
342
|
+
async up(trx, db) {
|
|
343
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
344
|
+
if (!hasTable) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
348
|
+
if (hasPolymorphicColumn) {
|
|
349
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
350
|
+
"strapi_release_actions",
|
|
351
|
+
"entry_document_id"
|
|
352
|
+
);
|
|
353
|
+
if (!hasEntryDocumentIdColumn) {
|
|
354
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
355
|
+
table.string("entry_document_id");
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
359
|
+
utils.async.map(releaseActions, async (action) => {
|
|
360
|
+
const { target_type, target_id } = action;
|
|
361
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
362
|
+
if (entry) {
|
|
363
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
async down() {
|
|
369
|
+
throw new Error("not implemented");
|
|
370
|
+
}
|
|
371
|
+
};
|
|
281
372
|
const register = async ({ strapi: strapi2 }) => {
|
|
282
373
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
283
374
|
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
375
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
284
376
|
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
285
377
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
286
378
|
}
|
|
@@ -290,6 +382,105 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
290
382
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
291
383
|
}
|
|
292
384
|
};
|
|
385
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
386
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
387
|
+
where: {
|
|
388
|
+
releasedAt: null,
|
|
389
|
+
actions: {
|
|
390
|
+
contentType,
|
|
391
|
+
entryDocumentId: entry.documentId,
|
|
392
|
+
locale: entry.locale
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
397
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).updateMany({
|
|
398
|
+
where: {
|
|
399
|
+
contentType,
|
|
400
|
+
entryDocumentId: entry.documentId,
|
|
401
|
+
locale: entry.locale
|
|
402
|
+
},
|
|
403
|
+
data: {
|
|
404
|
+
isEntryValid: entryStatus
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
for (const release2 of releases) {
|
|
408
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
412
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
413
|
+
where: {
|
|
414
|
+
actions: params
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
418
|
+
where: params
|
|
419
|
+
});
|
|
420
|
+
for (const release2 of releases) {
|
|
421
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
425
|
+
if (ctx.action !== "delete") {
|
|
426
|
+
return next();
|
|
427
|
+
}
|
|
428
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
429
|
+
return next();
|
|
430
|
+
}
|
|
431
|
+
const contentType = ctx.contentType.uid;
|
|
432
|
+
const { documentId, locale } = ctx.params;
|
|
433
|
+
const result = await next();
|
|
434
|
+
if (!result) {
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
try {
|
|
438
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
439
|
+
contentType,
|
|
440
|
+
entryDocumentId: documentId,
|
|
441
|
+
...locale !== "*" && { locale }
|
|
442
|
+
});
|
|
443
|
+
} catch (error) {
|
|
444
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
445
|
+
error
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return result;
|
|
449
|
+
};
|
|
450
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
451
|
+
if (ctx.action !== "update") {
|
|
452
|
+
return next();
|
|
453
|
+
}
|
|
454
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
455
|
+
return next();
|
|
456
|
+
}
|
|
457
|
+
const contentType = ctx.contentType.uid;
|
|
458
|
+
const result = await next();
|
|
459
|
+
if (!result) {
|
|
460
|
+
return result;
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
464
|
+
} catch (error) {
|
|
465
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
466
|
+
error
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
};
|
|
471
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
472
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
473
|
+
where: {
|
|
474
|
+
actions: params
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
478
|
+
where: params
|
|
479
|
+
});
|
|
480
|
+
for (const release2 of releases) {
|
|
481
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
482
|
+
}
|
|
483
|
+
};
|
|
293
484
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
294
485
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
295
486
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
@@ -297,115 +488,29 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
297
488
|
);
|
|
298
489
|
strapi2.db.lifecycles.subscribe({
|
|
299
490
|
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
491
|
/**
|
|
340
|
-
*
|
|
341
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
492
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
342
493
|
*/
|
|
343
494
|
async afterDeleteMany(event) {
|
|
344
495
|
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
|
-
}
|
|
496
|
+
const model = strapi2.getModel(event.model.uid);
|
|
497
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
498
|
+
const { where } = event.params;
|
|
499
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
500
|
+
contentType: model.uid,
|
|
501
|
+
locale: where?.locale ?? null,
|
|
502
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
365
503
|
});
|
|
366
|
-
for (const release2 of releases) {
|
|
367
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
368
|
-
}
|
|
369
504
|
}
|
|
370
505
|
} catch (error) {
|
|
371
506
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
372
507
|
error
|
|
373
508
|
});
|
|
374
509
|
}
|
|
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
510
|
}
|
|
408
511
|
});
|
|
512
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
513
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
409
514
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
410
515
|
strapi2.log.error(
|
|
411
516
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -497,15 +602,13 @@ const schema = {
|
|
|
497
602
|
enum: ["publish", "unpublish"],
|
|
498
603
|
required: true
|
|
499
604
|
},
|
|
500
|
-
entry: {
|
|
501
|
-
type: "relation",
|
|
502
|
-
relation: "morphToOne",
|
|
503
|
-
configurable: false
|
|
504
|
-
},
|
|
505
605
|
contentType: {
|
|
506
606
|
type: "string",
|
|
507
607
|
required: true
|
|
508
608
|
},
|
|
609
|
+
entryDocumentId: {
|
|
610
|
+
type: "string"
|
|
611
|
+
},
|
|
509
612
|
locale: {
|
|
510
613
|
type: "string"
|
|
511
614
|
},
|
|
@@ -527,18 +630,6 @@ const contentTypes = {
|
|
|
527
630
|
release: release$1,
|
|
528
631
|
"release-action": releaseAction$1
|
|
529
632
|
};
|
|
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
633
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
543
634
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
544
635
|
strapi2.eventHub.emit(event, {
|
|
@@ -547,93 +638,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
547
638
|
release: release2
|
|
548
639
|
});
|
|
549
640
|
};
|
|
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
641
|
const getFormattedActions = async (releaseId) => {
|
|
597
642
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
598
643
|
where: {
|
|
599
644
|
release: {
|
|
600
645
|
id: releaseId
|
|
601
646
|
}
|
|
602
|
-
},
|
|
603
|
-
populate: {
|
|
604
|
-
entry: {
|
|
605
|
-
fields: ["id"]
|
|
606
|
-
}
|
|
607
647
|
}
|
|
608
648
|
});
|
|
609
649
|
if (actions.length === 0) {
|
|
610
650
|
throw new utils.errors.ValidationError("No entries to publish");
|
|
611
651
|
}
|
|
612
|
-
const
|
|
613
|
-
const singleTypeActions = [];
|
|
652
|
+
const formattedActions = {};
|
|
614
653
|
for (const action of actions) {
|
|
615
654
|
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
|
-
});
|
|
655
|
+
if (!formattedActions[contentTypeUid]) {
|
|
656
|
+
formattedActions[contentTypeUid] = {
|
|
657
|
+
publish: [],
|
|
658
|
+
unpublish: []
|
|
659
|
+
};
|
|
634
660
|
}
|
|
661
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
662
|
+
documentId: action.entryDocumentId,
|
|
663
|
+
locale: action.locale
|
|
664
|
+
});
|
|
635
665
|
}
|
|
636
|
-
return
|
|
666
|
+
return formattedActions;
|
|
637
667
|
};
|
|
638
668
|
return {
|
|
639
669
|
async create(releaseData, { user }) {
|
|
@@ -680,91 +710,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
680
710
|
}
|
|
681
711
|
});
|
|
682
712
|
},
|
|
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;
|
|
713
|
+
findMany(query) {
|
|
714
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
715
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
716
|
+
...dbQuery
|
|
768
717
|
});
|
|
769
718
|
},
|
|
770
719
|
async update(id, releaseData, { user }) {
|
|
@@ -800,14 +749,218 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
800
749
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
801
750
|
return updatedRelease;
|
|
802
751
|
},
|
|
803
|
-
async
|
|
804
|
-
const
|
|
752
|
+
async getAllComponents() {
|
|
753
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
754
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
755
|
+
const componentsMap = components.reduce(
|
|
756
|
+
(acc, component) => {
|
|
757
|
+
acc[component.uid] = component;
|
|
758
|
+
return acc;
|
|
759
|
+
},
|
|
760
|
+
{}
|
|
761
|
+
);
|
|
762
|
+
return componentsMap;
|
|
763
|
+
},
|
|
764
|
+
async delete(releaseId) {
|
|
765
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
766
|
+
where: { id: releaseId },
|
|
767
|
+
populate: {
|
|
768
|
+
actions: {
|
|
769
|
+
select: ["id"]
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
if (!release2) {
|
|
774
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
775
|
+
}
|
|
776
|
+
if (release2.releasedAt) {
|
|
777
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
778
|
+
}
|
|
779
|
+
await strapi2.db.transaction(async () => {
|
|
780
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
781
|
+
where: {
|
|
782
|
+
id: {
|
|
783
|
+
$in: release2.actions.map((action) => action.id)
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
788
|
+
where: {
|
|
789
|
+
id: releaseId
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
if (release2.scheduledAt) {
|
|
794
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
795
|
+
await schedulingService.cancel(release2.id);
|
|
796
|
+
}
|
|
797
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
798
|
+
return release2;
|
|
799
|
+
},
|
|
800
|
+
async publish(releaseId) {
|
|
801
|
+
const {
|
|
802
|
+
release: release2,
|
|
803
|
+
error
|
|
804
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
805
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
806
|
+
if (!lockedRelease) {
|
|
807
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
808
|
+
}
|
|
809
|
+
if (lockedRelease.releasedAt) {
|
|
810
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
811
|
+
}
|
|
812
|
+
if (lockedRelease.status === "failed") {
|
|
813
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
814
|
+
}
|
|
815
|
+
try {
|
|
816
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
817
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
818
|
+
await strapi2.db.transaction(
|
|
819
|
+
async () => Promise.all(
|
|
820
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
821
|
+
const contentType = contentTypeUid;
|
|
822
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
823
|
+
return Promise.all([
|
|
824
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
825
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
826
|
+
]);
|
|
827
|
+
})
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
831
|
+
where: {
|
|
832
|
+
id: releaseId
|
|
833
|
+
},
|
|
834
|
+
data: {
|
|
835
|
+
status: "done",
|
|
836
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
840
|
+
isPublished: true,
|
|
841
|
+
release: release22
|
|
842
|
+
});
|
|
843
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
844
|
+
return { release: release22, error: null };
|
|
845
|
+
} catch (error2) {
|
|
846
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
847
|
+
isPublished: false,
|
|
848
|
+
error: error2
|
|
849
|
+
});
|
|
850
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
851
|
+
status: "failed"
|
|
852
|
+
}).transacting(trx).execute();
|
|
853
|
+
return {
|
|
854
|
+
release: null,
|
|
855
|
+
error: error2
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
if (error instanceof Error) {
|
|
860
|
+
throw error;
|
|
861
|
+
}
|
|
862
|
+
return release2;
|
|
863
|
+
},
|
|
864
|
+
async updateReleaseStatus(releaseId) {
|
|
865
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
866
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
867
|
+
releaseActionService.countActions({
|
|
868
|
+
filters: {
|
|
869
|
+
release: releaseId
|
|
870
|
+
}
|
|
871
|
+
}),
|
|
872
|
+
releaseActionService.countActions({
|
|
873
|
+
filters: {
|
|
874
|
+
release: releaseId,
|
|
875
|
+
isEntryValid: false
|
|
876
|
+
}
|
|
877
|
+
})
|
|
878
|
+
]);
|
|
879
|
+
if (totalActions > 0) {
|
|
880
|
+
if (invalidActions > 0) {
|
|
881
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
882
|
+
where: {
|
|
883
|
+
id: releaseId
|
|
884
|
+
},
|
|
885
|
+
data: {
|
|
886
|
+
status: "blocked"
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
891
|
+
where: {
|
|
892
|
+
id: releaseId
|
|
893
|
+
},
|
|
894
|
+
data: {
|
|
895
|
+
status: "ready"
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
900
|
+
where: {
|
|
901
|
+
id: releaseId
|
|
902
|
+
},
|
|
903
|
+
data: {
|
|
904
|
+
status: "empty"
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
};
|
|
910
|
+
const getGroupName = (queryValue) => {
|
|
911
|
+
switch (queryValue) {
|
|
912
|
+
case "contentType":
|
|
913
|
+
return "contentType.displayName";
|
|
914
|
+
case "type":
|
|
915
|
+
return "type";
|
|
916
|
+
case "locale":
|
|
917
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
918
|
+
default:
|
|
919
|
+
return "contentType.displayName";
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
923
|
+
const getLocalesDataForActions = async () => {
|
|
924
|
+
if (!strapi2.plugin("i18n")) {
|
|
925
|
+
return {};
|
|
926
|
+
}
|
|
927
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
928
|
+
return allLocales.reduce((acc, locale) => {
|
|
929
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
930
|
+
return acc;
|
|
931
|
+
}, {});
|
|
932
|
+
};
|
|
933
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
934
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
935
|
+
const contentTypesData = {};
|
|
936
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
937
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
938
|
+
uid: contentTypeUid
|
|
939
|
+
});
|
|
940
|
+
contentTypesData[contentTypeUid] = {
|
|
941
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
942
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
return contentTypesData;
|
|
946
|
+
};
|
|
947
|
+
return {
|
|
948
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
949
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
805
950
|
strapi: strapi2
|
|
806
951
|
});
|
|
807
952
|
await Promise.all([
|
|
808
|
-
|
|
953
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
809
954
|
validateUniqueEntry(releaseId, action)
|
|
810
955
|
]);
|
|
956
|
+
const model = strapi2.contentType(action.contentType);
|
|
957
|
+
if (model.kind === "singleType") {
|
|
958
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
959
|
+
if (!document) {
|
|
960
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
961
|
+
}
|
|
962
|
+
action.entryDocumentId = document.documentId;
|
|
963
|
+
}
|
|
811
964
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
812
965
|
if (!release2) {
|
|
813
966
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
@@ -815,28 +968,30 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
815
968
|
if (release2.releasedAt) {
|
|
816
969
|
throw new utils.errors.ValidationError("Release already published");
|
|
817
970
|
}
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
971
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
972
|
+
{
|
|
973
|
+
contentType: action.contentType,
|
|
974
|
+
documentId: action.entryDocumentId,
|
|
975
|
+
locale: action.locale
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
strapi: strapi2
|
|
979
|
+
}
|
|
980
|
+
) : true;
|
|
821
981
|
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
822
982
|
data: {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
isEntryValid,
|
|
827
|
-
entry: {
|
|
828
|
-
id: entry.id,
|
|
829
|
-
__type: entry.contentType,
|
|
830
|
-
__pivot: { field: "entry" }
|
|
831
|
-
},
|
|
832
|
-
release: releaseId
|
|
983
|
+
...action,
|
|
984
|
+
release: release2.id,
|
|
985
|
+
isEntryValid: actionStatus
|
|
833
986
|
},
|
|
834
|
-
populate: { release: { select: ["id"] }
|
|
987
|
+
populate: { release: { select: ["id"] } }
|
|
835
988
|
});
|
|
836
|
-
|
|
989
|
+
if (!disableUpdateReleaseStatus) {
|
|
990
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
991
|
+
}
|
|
837
992
|
return releaseAction2;
|
|
838
993
|
},
|
|
839
|
-
async
|
|
994
|
+
async findPage(releaseId, query) {
|
|
840
995
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
841
996
|
where: { id: releaseId },
|
|
842
997
|
select: ["id"]
|
|
@@ -845,21 +1000,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
845
1000
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
846
1001
|
}
|
|
847
1002
|
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
848
|
-
|
|
1003
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
849
1004
|
...dbQuery,
|
|
850
|
-
populate: {
|
|
851
|
-
entry: {
|
|
852
|
-
populate: "*"
|
|
853
|
-
}
|
|
854
|
-
},
|
|
855
1005
|
where: {
|
|
856
1006
|
release: releaseId
|
|
857
1007
|
}
|
|
858
1008
|
});
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1009
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
1010
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
1011
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1012
|
+
const entry = await getEntry(
|
|
1013
|
+
{
|
|
1014
|
+
contentType: action.contentType,
|
|
1015
|
+
documentId: action.entryDocumentId,
|
|
1016
|
+
locale: action.locale,
|
|
1017
|
+
populate,
|
|
1018
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
1019
|
+
},
|
|
1020
|
+
{ strapi: strapi2 }
|
|
1021
|
+
);
|
|
1022
|
+
return {
|
|
1023
|
+
...action,
|
|
1024
|
+
entry,
|
|
1025
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1026
|
+
};
|
|
1027
|
+
});
|
|
1028
|
+
return {
|
|
1029
|
+
results: actionsWithEntry,
|
|
1030
|
+
pagination
|
|
1031
|
+
};
|
|
863
1032
|
},
|
|
864
1033
|
async groupActions(actions, groupBy) {
|
|
865
1034
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -868,8 +1037,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
868
1037
|
}
|
|
869
1038
|
return acc;
|
|
870
1039
|
}, []);
|
|
871
|
-
const allReleaseContentTypesDictionary = await
|
|
872
|
-
const allLocalesDictionary = await
|
|
1040
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1041
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
873
1042
|
const formattedData = actions.map((action) => {
|
|
874
1043
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
875
1044
|
return {
|
|
@@ -881,165 +1050,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
881
1050
|
uid: action.contentType
|
|
882
1051
|
}
|
|
883
1052
|
};
|
|
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;
|
|
1053
|
+
});
|
|
1054
|
+
const groupName = getGroupName(groupBy);
|
|
1055
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
975
1056
|
},
|
|
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");
|
|
1057
|
+
async getContentTypeModelsFromActions(actions) {
|
|
1058
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1059
|
+
if (!acc.includes(action.contentType)) {
|
|
1060
|
+
acc.push(action.contentType);
|
|
990
1061
|
}
|
|
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
|
|
1062
|
+
return acc;
|
|
1063
|
+
}, []);
|
|
1064
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
1065
|
+
const contentTypeModelsMap = await utils.async.reduce(contentTypeUids)(
|
|
1066
|
+
async (accPromise, contentTypeUid) => {
|
|
1067
|
+
const acc = await accPromise;
|
|
1068
|
+
const contentTypeModel = strapi2.getModel(contentTypeUid);
|
|
1069
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
1070
|
+
populate: "stageRequiredToPublish"
|
|
1026
1071
|
});
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
release: null,
|
|
1032
|
-
error: error2
|
|
1072
|
+
acc[contentTypeUid] = {
|
|
1073
|
+
...contentTypeModel,
|
|
1074
|
+
hasReviewWorkflow: !!workflow,
|
|
1075
|
+
stageRequiredToPublish: workflow?.stageRequiredToPublish
|
|
1033
1076
|
};
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
return release2;
|
|
1077
|
+
return acc;
|
|
1078
|
+
},
|
|
1079
|
+
{}
|
|
1080
|
+
);
|
|
1081
|
+
return contentTypeModelsMap;
|
|
1040
1082
|
},
|
|
1041
|
-
async
|
|
1042
|
-
const
|
|
1083
|
+
async countActions(query) {
|
|
1084
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1085
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1086
|
+
},
|
|
1087
|
+
async update(actionId, releaseId, update) {
|
|
1088
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1043
1089
|
where: {
|
|
1044
1090
|
id: actionId,
|
|
1045
1091
|
release: {
|
|
@@ -1048,17 +1094,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1048
1094
|
$null: true
|
|
1049
1095
|
}
|
|
1050
1096
|
}
|
|
1051
|
-
}
|
|
1052
|
-
data: update
|
|
1097
|
+
}
|
|
1053
1098
|
});
|
|
1054
|
-
if (!
|
|
1099
|
+
if (!action) {
|
|
1055
1100
|
throw new utils.errors.NotFoundError(
|
|
1056
1101
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1057
1102
|
);
|
|
1058
1103
|
}
|
|
1104
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1105
|
+
{
|
|
1106
|
+
contentType: action.contentType,
|
|
1107
|
+
documentId: action.entryDocumentId,
|
|
1108
|
+
locale: action.locale
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
strapi: strapi2
|
|
1112
|
+
}
|
|
1113
|
+
) : true;
|
|
1114
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1115
|
+
where: {
|
|
1116
|
+
id: actionId,
|
|
1117
|
+
release: {
|
|
1118
|
+
id: releaseId,
|
|
1119
|
+
releasedAt: {
|
|
1120
|
+
$null: true
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
1124
|
+
data: {
|
|
1125
|
+
...update,
|
|
1126
|
+
isEntryValid: actionStatus
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1059
1130
|
return updatedAction;
|
|
1060
1131
|
},
|
|
1061
|
-
async
|
|
1132
|
+
async delete(actionId, releaseId) {
|
|
1062
1133
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1063
1134
|
where: {
|
|
1064
1135
|
id: actionId,
|
|
@@ -1075,51 +1146,56 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1075
1146
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1076
1147
|
);
|
|
1077
1148
|
}
|
|
1078
|
-
|
|
1149
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1079
1150
|
return deletedAction;
|
|
1080
1151
|
},
|
|
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"
|
|
1152
|
+
async validateActionsByContentTypes(contentTypeUids) {
|
|
1153
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
1154
|
+
where: {
|
|
1155
|
+
contentType: {
|
|
1156
|
+
$in: contentTypeUids
|
|
1157
|
+
},
|
|
1158
|
+
// We only want to validate actions that are going to be published
|
|
1159
|
+
type: "publish",
|
|
1160
|
+
release: {
|
|
1161
|
+
releasedAt: {
|
|
1162
|
+
$null: true
|
|
1103
1163
|
}
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1164
|
+
}
|
|
1165
|
+
},
|
|
1166
|
+
populate: { release: true }
|
|
1167
|
+
});
|
|
1168
|
+
const releasesUpdated = [];
|
|
1169
|
+
await utils.async.map(actions, async (action) => {
|
|
1170
|
+
const isValid = await getDraftEntryValidStatus(
|
|
1171
|
+
{
|
|
1172
|
+
contentType: action.contentType,
|
|
1173
|
+
documentId: action.entryDocumentId,
|
|
1174
|
+
locale: action.locale
|
|
1175
|
+
},
|
|
1176
|
+
{ strapi: strapi2 }
|
|
1177
|
+
);
|
|
1178
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1107
1179
|
where: {
|
|
1108
|
-
id:
|
|
1180
|
+
id: action.id
|
|
1109
1181
|
},
|
|
1110
1182
|
data: {
|
|
1111
|
-
|
|
1183
|
+
isEntryValid: isValid
|
|
1112
1184
|
}
|
|
1113
1185
|
});
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
where: {
|
|
1117
|
-
id: releaseId
|
|
1118
|
-
},
|
|
1119
|
-
data: {
|
|
1120
|
-
status: "empty"
|
|
1186
|
+
if (!releasesUpdated.includes(action.release.id)) {
|
|
1187
|
+
releasesUpdated.push(action.release.id);
|
|
1121
1188
|
}
|
|
1189
|
+
return {
|
|
1190
|
+
id: action.id,
|
|
1191
|
+
isEntryValid: isValid
|
|
1192
|
+
};
|
|
1122
1193
|
});
|
|
1194
|
+
if (releasesUpdated.length > 0) {
|
|
1195
|
+
await utils.async.map(releasesUpdated, async (releaseId) => {
|
|
1196
|
+
await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1123
1199
|
}
|
|
1124
1200
|
};
|
|
1125
1201
|
};
|
|
@@ -1135,30 +1211,35 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1135
1211
|
where: {
|
|
1136
1212
|
id: releaseId
|
|
1137
1213
|
},
|
|
1138
|
-
populate: {
|
|
1214
|
+
populate: {
|
|
1215
|
+
actions: true
|
|
1216
|
+
}
|
|
1139
1217
|
});
|
|
1140
1218
|
if (!release2) {
|
|
1141
1219
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1142
1220
|
}
|
|
1143
1221
|
const isEntryInRelease = release2.actions.some(
|
|
1144
|
-
(action) =>
|
|
1222
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1145
1223
|
);
|
|
1146
1224
|
if (isEntryInRelease) {
|
|
1147
1225
|
throw new AlreadyOnReleaseError(
|
|
1148
|
-
`Entry with
|
|
1226
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1149
1227
|
);
|
|
1150
1228
|
}
|
|
1151
1229
|
},
|
|
1152
|
-
|
|
1230
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1153
1231
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1154
1232
|
if (!contentType) {
|
|
1155
1233
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1156
1234
|
}
|
|
1157
|
-
if (!contentType
|
|
1235
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1158
1236
|
throw new utils.errors.ValidationError(
|
|
1159
1237
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1160
1238
|
);
|
|
1161
1239
|
}
|
|
1240
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1241
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1242
|
+
}
|
|
1162
1243
|
},
|
|
1163
1244
|
async validatePendingReleasesLimit() {
|
|
1164
1245
|
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
@@ -1247,78 +1328,165 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1247
1328
|
}
|
|
1248
1329
|
};
|
|
1249
1330
|
};
|
|
1331
|
+
const DEFAULT_SETTINGS = {
|
|
1332
|
+
defaultTimezone: null
|
|
1333
|
+
};
|
|
1334
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1335
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1336
|
+
return {
|
|
1337
|
+
async update({ settings: settings2 }) {
|
|
1338
|
+
const store = await getStore();
|
|
1339
|
+
store.set({ key: "settings", value: settings2 });
|
|
1340
|
+
return settings2;
|
|
1341
|
+
},
|
|
1342
|
+
async find() {
|
|
1343
|
+
const store = await getStore();
|
|
1344
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1345
|
+
return {
|
|
1346
|
+
...DEFAULT_SETTINGS,
|
|
1347
|
+
...settings2 || {}
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
};
|
|
1351
|
+
};
|
|
1250
1352
|
const services = {
|
|
1251
1353
|
release: createReleaseService,
|
|
1354
|
+
"release-action": createReleaseActionService,
|
|
1252
1355
|
"release-validation": createReleaseValidationService,
|
|
1253
|
-
scheduling: createSchedulingService
|
|
1356
|
+
scheduling: createSchedulingService,
|
|
1357
|
+
settings: createSettingsService
|
|
1254
1358
|
};
|
|
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()
|
|
1359
|
+
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1360
|
+
name: utils.yup.string().trim().required(),
|
|
1361
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1362
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1363
|
+
is: (value) => value !== null && value !== void 0,
|
|
1364
|
+
then: utils.yup.string().required(),
|
|
1365
|
+
otherwise: utils.yup.string().nullable()
|
|
1273
1366
|
})
|
|
1274
1367
|
}).required().noUnknown();
|
|
1368
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1369
|
+
contentType: utils.yup.string().required(),
|
|
1370
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1371
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1372
|
+
locale: utils.yup.string().nullable()
|
|
1373
|
+
}).required().noUnknown();
|
|
1275
1374
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1375
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1376
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1377
|
+
);
|
|
1276
1378
|
const releaseController = {
|
|
1277
|
-
|
|
1379
|
+
/**
|
|
1380
|
+
* Find releases based on documents attached or not to the release.
|
|
1381
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1382
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1383
|
+
*/
|
|
1384
|
+
async findByDocumentAttached(ctx) {
|
|
1278
1385
|
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1279
1386
|
ability: ctx.state.userAbility,
|
|
1280
1387
|
model: RELEASE_MODEL_UID
|
|
1281
1388
|
});
|
|
1282
1389
|
await permissionsManager.validateQuery(ctx.query);
|
|
1283
1390
|
const releaseService = getService("release", { strapi });
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1391
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1392
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1393
|
+
const model = strapi.getModel(query.contentType);
|
|
1394
|
+
if (model.kind && model.kind === "singleType") {
|
|
1395
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1396
|
+
if (!document) {
|
|
1397
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1398
|
+
}
|
|
1399
|
+
query.entryDocumentId = document.documentId;
|
|
1400
|
+
}
|
|
1401
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1402
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1403
|
+
if (isEntryAttached) {
|
|
1404
|
+
const releases = await releaseService.findMany({
|
|
1405
|
+
where: {
|
|
1406
|
+
releasedAt: null,
|
|
1407
|
+
actions: {
|
|
1408
|
+
contentType,
|
|
1409
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1410
|
+
locale: locale ?? null
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
populate: {
|
|
1299
1414
|
actions: {
|
|
1300
|
-
|
|
1301
|
-
|
|
1415
|
+
fields: ["type"],
|
|
1416
|
+
filters: {
|
|
1417
|
+
contentType,
|
|
1418
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1419
|
+
locale: locale ?? null
|
|
1302
1420
|
}
|
|
1303
1421
|
}
|
|
1304
|
-
}
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
ctx.body = { data: releases };
|
|
1425
|
+
} else {
|
|
1426
|
+
const relatedReleases = await releaseService.findMany({
|
|
1427
|
+
where: {
|
|
1428
|
+
releasedAt: null,
|
|
1429
|
+
actions: {
|
|
1430
|
+
contentType,
|
|
1431
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1432
|
+
locale: locale ?? null
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1305
1435
|
});
|
|
1306
|
-
const
|
|
1436
|
+
const releases = await releaseService.findMany({
|
|
1307
1437
|
where: {
|
|
1438
|
+
$or: [
|
|
1439
|
+
{
|
|
1440
|
+
id: {
|
|
1441
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
{
|
|
1445
|
+
actions: null
|
|
1446
|
+
}
|
|
1447
|
+
],
|
|
1308
1448
|
releasedAt: null
|
|
1309
1449
|
}
|
|
1310
1450
|
});
|
|
1311
|
-
ctx.body = { data
|
|
1451
|
+
ctx.body = { data: releases };
|
|
1312
1452
|
}
|
|
1313
1453
|
},
|
|
1454
|
+
async findPage(ctx) {
|
|
1455
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1456
|
+
ability: ctx.state.userAbility,
|
|
1457
|
+
model: RELEASE_MODEL_UID
|
|
1458
|
+
});
|
|
1459
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1460
|
+
const releaseService = getService("release", { strapi });
|
|
1461
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1462
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1463
|
+
const data = results.map((release2) => {
|
|
1464
|
+
const { actions, ...releaseData } = release2;
|
|
1465
|
+
return {
|
|
1466
|
+
...releaseData,
|
|
1467
|
+
actions: {
|
|
1468
|
+
meta: {
|
|
1469
|
+
count: actions.count
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
});
|
|
1474
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1475
|
+
where: {
|
|
1476
|
+
releasedAt: null
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1480
|
+
},
|
|
1314
1481
|
async findOne(ctx) {
|
|
1315
1482
|
const id = ctx.params.id;
|
|
1316
1483
|
const releaseService = getService("release", { strapi });
|
|
1484
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1317
1485
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1318
1486
|
if (!release2) {
|
|
1319
1487
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1320
1488
|
}
|
|
1321
|
-
const count = await
|
|
1489
|
+
const count = await releaseActionService.countActions({
|
|
1322
1490
|
filters: {
|
|
1323
1491
|
release: id
|
|
1324
1492
|
}
|
|
@@ -1338,28 +1506,43 @@ const releaseController = {
|
|
|
1338
1506
|
ctx.body = { data };
|
|
1339
1507
|
},
|
|
1340
1508
|
async mapEntriesToReleases(ctx) {
|
|
1341
|
-
const { contentTypeUid,
|
|
1342
|
-
if (!contentTypeUid || !
|
|
1509
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1510
|
+
if (!contentTypeUid || !documentIds) {
|
|
1343
1511
|
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1344
1512
|
}
|
|
1345
1513
|
const releaseService = getService("release", { strapi });
|
|
1346
|
-
const releasesWithActions = await releaseService.
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1514
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1515
|
+
where: {
|
|
1516
|
+
releasedAt: null,
|
|
1517
|
+
actions: {
|
|
1518
|
+
contentType: contentTypeUid,
|
|
1519
|
+
entryDocumentId: {
|
|
1520
|
+
$in: documentIds
|
|
1521
|
+
},
|
|
1522
|
+
locale
|
|
1523
|
+
}
|
|
1524
|
+
},
|
|
1525
|
+
populate: {
|
|
1526
|
+
actions: true
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1350
1529
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1351
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1352
1530
|
(acc, release2) => {
|
|
1353
1531
|
release2.actions.forEach((action) => {
|
|
1354
|
-
if (
|
|
1355
|
-
|
|
1532
|
+
if (action.contentType !== contentTypeUid) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
if (locale && action.locale !== locale) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
if (!acc[action.entryDocumentId]) {
|
|
1539
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1356
1540
|
} else {
|
|
1357
|
-
acc[action.
|
|
1541
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1358
1542
|
}
|
|
1359
1543
|
});
|
|
1360
1544
|
return acc;
|
|
1361
1545
|
},
|
|
1362
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1363
1546
|
{}
|
|
1364
1547
|
);
|
|
1365
1548
|
ctx.body = {
|
|
@@ -1404,18 +1587,18 @@ const releaseController = {
|
|
|
1404
1587
|
};
|
|
1405
1588
|
},
|
|
1406
1589
|
async publish(ctx) {
|
|
1407
|
-
const user = ctx.state.user;
|
|
1408
1590
|
const id = ctx.params.id;
|
|
1409
1591
|
const releaseService = getService("release", { strapi });
|
|
1410
|
-
const
|
|
1592
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1593
|
+
const release2 = await releaseService.publish(id);
|
|
1411
1594
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1412
|
-
|
|
1595
|
+
releaseActionService.countActions({
|
|
1413
1596
|
filters: {
|
|
1414
1597
|
release: id,
|
|
1415
1598
|
type: "publish"
|
|
1416
1599
|
}
|
|
1417
1600
|
}),
|
|
1418
|
-
|
|
1601
|
+
releaseActionService.countActions({
|
|
1419
1602
|
filters: {
|
|
1420
1603
|
release: id,
|
|
1421
1604
|
type: "unpublish"
|
|
@@ -1433,24 +1616,27 @@ const releaseController = {
|
|
|
1433
1616
|
}
|
|
1434
1617
|
};
|
|
1435
1618
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
}).required(),
|
|
1619
|
+
contentType: utils.yup.string().required(),
|
|
1620
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1621
|
+
locale: utils.yup.string(),
|
|
1440
1622
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1441
1623
|
});
|
|
1442
1624
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1443
1625
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1444
1626
|
});
|
|
1627
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1628
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1629
|
+
});
|
|
1445
1630
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1446
1631
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1632
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1447
1633
|
const releaseActionController = {
|
|
1448
1634
|
async create(ctx) {
|
|
1449
1635
|
const releaseId = ctx.params.releaseId;
|
|
1450
1636
|
const releaseActionArgs = ctx.request.body;
|
|
1451
1637
|
await validateReleaseAction(releaseActionArgs);
|
|
1452
|
-
const
|
|
1453
|
-
const releaseAction2 = await
|
|
1638
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1639
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1454
1640
|
ctx.created({
|
|
1455
1641
|
data: releaseAction2
|
|
1456
1642
|
});
|
|
@@ -1461,12 +1647,15 @@ const releaseActionController = {
|
|
|
1461
1647
|
await Promise.all(
|
|
1462
1648
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1463
1649
|
);
|
|
1650
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1464
1651
|
const releaseService = getService("release", { strapi });
|
|
1465
1652
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1466
1653
|
const releaseActions2 = await Promise.all(
|
|
1467
1654
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1468
1655
|
try {
|
|
1469
|
-
const action = await
|
|
1656
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1657
|
+
disableUpdateReleaseStatus: true
|
|
1658
|
+
});
|
|
1470
1659
|
return action;
|
|
1471
1660
|
} catch (error) {
|
|
1472
1661
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1479,6 +1668,9 @@ const releaseActionController = {
|
|
|
1479
1668
|
return releaseActions2;
|
|
1480
1669
|
});
|
|
1481
1670
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1671
|
+
if (newReleaseActions.length > 0) {
|
|
1672
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1673
|
+
}
|
|
1482
1674
|
ctx.created({
|
|
1483
1675
|
data: newReleaseActions,
|
|
1484
1676
|
meta: {
|
|
@@ -1493,10 +1685,17 @@ const releaseActionController = {
|
|
|
1493
1685
|
ability: ctx.state.userAbility,
|
|
1494
1686
|
model: RELEASE_ACTION_MODEL_UID
|
|
1495
1687
|
});
|
|
1688
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1689
|
+
if (ctx.query.groupBy) {
|
|
1690
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1691
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1695
|
+
delete ctx.query.groupBy;
|
|
1496
1696
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1497
|
-
const
|
|
1498
|
-
const { results, pagination } = await
|
|
1499
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1697
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1698
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1500
1699
|
...query
|
|
1501
1700
|
});
|
|
1502
1701
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
@@ -1512,10 +1711,11 @@ const releaseActionController = {
|
|
|
1512
1711
|
}, {});
|
|
1513
1712
|
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1514
1713
|
...action,
|
|
1515
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1714
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1516
1715
|
}));
|
|
1517
|
-
const groupedData = await
|
|
1518
|
-
const contentTypes2 =
|
|
1716
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1717
|
+
const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
|
|
1718
|
+
const releaseService = getService("release", { strapi });
|
|
1519
1719
|
const components = await releaseService.getAllComponents();
|
|
1520
1720
|
ctx.body = {
|
|
1521
1721
|
data: groupedData,
|
|
@@ -1531,8 +1731,8 @@ const releaseActionController = {
|
|
|
1531
1731
|
const releaseId = ctx.params.releaseId;
|
|
1532
1732
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1533
1733
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1534
|
-
const
|
|
1535
|
-
const updatedAction = await
|
|
1734
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1735
|
+
const updatedAction = await releaseActionService.update(
|
|
1536
1736
|
actionId,
|
|
1537
1737
|
releaseId,
|
|
1538
1738
|
releaseActionUpdateArgs
|
|
@@ -1544,14 +1744,36 @@ const releaseActionController = {
|
|
|
1544
1744
|
async delete(ctx) {
|
|
1545
1745
|
const actionId = ctx.params.actionId;
|
|
1546
1746
|
const releaseId = ctx.params.releaseId;
|
|
1547
|
-
const
|
|
1548
|
-
const deletedReleaseAction = await
|
|
1747
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1748
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1549
1749
|
ctx.body = {
|
|
1550
1750
|
data: deletedReleaseAction
|
|
1551
1751
|
};
|
|
1552
1752
|
}
|
|
1553
1753
|
};
|
|
1554
|
-
const
|
|
1754
|
+
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1755
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1756
|
+
}).required().noUnknown();
|
|
1757
|
+
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1758
|
+
const settingsController = {
|
|
1759
|
+
async find(ctx) {
|
|
1760
|
+
const settingsService = getService("settings", { strapi });
|
|
1761
|
+
const settings2 = await settingsService.find();
|
|
1762
|
+
ctx.body = { data: settings2 };
|
|
1763
|
+
},
|
|
1764
|
+
async update(ctx) {
|
|
1765
|
+
const settingsBody = ctx.request.body;
|
|
1766
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1767
|
+
const settingsService = getService("settings", { strapi });
|
|
1768
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1769
|
+
ctx.body = { data: updatedSettings };
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
const controllers = {
|
|
1773
|
+
release: releaseController,
|
|
1774
|
+
"release-action": releaseActionController,
|
|
1775
|
+
settings: settingsController
|
|
1776
|
+
};
|
|
1555
1777
|
const release = {
|
|
1556
1778
|
type: "admin",
|
|
1557
1779
|
routes: [
|
|
@@ -1571,6 +1793,22 @@ const release = {
|
|
|
1571
1793
|
]
|
|
1572
1794
|
}
|
|
1573
1795
|
},
|
|
1796
|
+
{
|
|
1797
|
+
method: "GET",
|
|
1798
|
+
path: "/getByDocumentAttached",
|
|
1799
|
+
handler: "release.findByDocumentAttached",
|
|
1800
|
+
config: {
|
|
1801
|
+
policies: [
|
|
1802
|
+
"admin::isAuthenticatedAdmin",
|
|
1803
|
+
{
|
|
1804
|
+
name: "admin::hasPermissions",
|
|
1805
|
+
config: {
|
|
1806
|
+
actions: ["plugin::content-releases.read"]
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
]
|
|
1810
|
+
}
|
|
1811
|
+
},
|
|
1574
1812
|
{
|
|
1575
1813
|
method: "POST",
|
|
1576
1814
|
path: "/",
|
|
@@ -1590,7 +1828,7 @@ const release = {
|
|
|
1590
1828
|
{
|
|
1591
1829
|
method: "GET",
|
|
1592
1830
|
path: "/",
|
|
1593
|
-
handler: "release.
|
|
1831
|
+
handler: "release.findPage",
|
|
1594
1832
|
config: {
|
|
1595
1833
|
policies: [
|
|
1596
1834
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1754,7 +1992,45 @@ const releaseAction = {
|
|
|
1754
1992
|
}
|
|
1755
1993
|
]
|
|
1756
1994
|
};
|
|
1995
|
+
const settings = {
|
|
1996
|
+
type: "admin",
|
|
1997
|
+
routes: [
|
|
1998
|
+
{
|
|
1999
|
+
method: "GET",
|
|
2000
|
+
path: "/settings",
|
|
2001
|
+
handler: "settings.find",
|
|
2002
|
+
config: {
|
|
2003
|
+
policies: [
|
|
2004
|
+
"admin::isAuthenticatedAdmin",
|
|
2005
|
+
{
|
|
2006
|
+
name: "admin::hasPermissions",
|
|
2007
|
+
config: {
|
|
2008
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
]
|
|
2012
|
+
}
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
method: "PUT",
|
|
2016
|
+
path: "/settings",
|
|
2017
|
+
handler: "settings.update",
|
|
2018
|
+
config: {
|
|
2019
|
+
policies: [
|
|
2020
|
+
"admin::isAuthenticatedAdmin",
|
|
2021
|
+
{
|
|
2022
|
+
name: "admin::hasPermissions",
|
|
2023
|
+
config: {
|
|
2024
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
]
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
]
|
|
2031
|
+
};
|
|
1757
2032
|
const routes = {
|
|
2033
|
+
settings,
|
|
1758
2034
|
release,
|
|
1759
2035
|
"release-action": releaseAction
|
|
1760
2036
|
};
|