@strapi/content-releases 0.0.0-experimental.d954d57341a6623992a0d211daaec8e245c3517d → 0.0.0-experimental.da85533897155e719d784f0271223c866d2f69ab
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-Do-Rnv0A.mjs → App-B4mkcLmw.mjs} +296 -263
- package/dist/_chunks/App-B4mkcLmw.mjs.map +1 -0
- package/dist/_chunks/{App-CqbuK4M6.js → App-DpoC8s97.js} +293 -261
- package/dist/_chunks/App-DpoC8s97.js.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-B89WWWJf.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-B89WWWJf.js.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-DfL6yxLG.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-DfL6yxLG.mjs.map +1 -0
- package/dist/_chunks/{en-DtFJ5ViE.js → en-CmYoEnA7.js} +9 -2
- package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
- package/dist/_chunks/{en-B9Ur3VsE.mjs → en-D0yVZFqf.mjs} +9 -2
- package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
- package/dist/_chunks/{index-D_pgdqQL.mjs → index-B3cqcIza.mjs} +780 -448
- package/dist/_chunks/index-B3cqcIza.mjs.map +1 -0
- package/dist/_chunks/{index-Tedsw4GC.js → index-sGcuP2hw.js} +763 -431
- package/dist/_chunks/index-sGcuP2hw.js.map +1 -0
- package/dist/_chunks/schemas-63pFihNF.mjs +44 -0
- package/dist/_chunks/schemas-63pFihNF.mjs.map +1 -0
- package/dist/_chunks/schemas-z5zp-_Gd.js +62 -0
- package/dist/_chunks/schemas-z5zp-_Gd.js.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +2 -2
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +2 -2
- 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/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 +43 -36
- 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 +796 -623
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +797 -624
- 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 +66 -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 +38 -38
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/release-action.d.ts +36 -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 +9 -10
- 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 +10 -9
- package/dist/_chunks/App-CqbuK4M6.js.map +0 -1
- package/dist/_chunks/App-Do-Rnv0A.mjs.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-D_pgdqQL.mjs.map +0 -1
- package/dist/_chunks/index-Tedsw4GC.js.map +0 -1
- package/dist/shared/validation-schemas.d.ts +0 -2
- package/dist/shared/validation-schemas.d.ts.map +0 -1
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),
|
|
@@ -79,6 +93,38 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) =
|
|
|
79
93
|
return false;
|
|
80
94
|
}
|
|
81
95
|
};
|
|
96
|
+
const getEntry = async ({
|
|
97
|
+
contentType,
|
|
98
|
+
documentId,
|
|
99
|
+
locale,
|
|
100
|
+
populate,
|
|
101
|
+
status = "draft"
|
|
102
|
+
}, { strapi: strapi2 }) => {
|
|
103
|
+
if (documentId) {
|
|
104
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
105
|
+
}
|
|
106
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
107
|
+
};
|
|
108
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
109
|
+
if (entry.publishedAt) {
|
|
110
|
+
return "published";
|
|
111
|
+
}
|
|
112
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
113
|
+
documentId: entry.documentId,
|
|
114
|
+
locale: entry.locale,
|
|
115
|
+
status: "published",
|
|
116
|
+
fields: ["updatedAt"]
|
|
117
|
+
});
|
|
118
|
+
if (!publishedEntry) {
|
|
119
|
+
return "draft";
|
|
120
|
+
}
|
|
121
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
122
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
123
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
124
|
+
return "modified";
|
|
125
|
+
}
|
|
126
|
+
return "published";
|
|
127
|
+
};
|
|
82
128
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
83
129
|
oldContentTypes,
|
|
84
130
|
contentTypes: contentTypes2
|
|
@@ -124,20 +170,22 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
124
170
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
125
171
|
for (const action of notValidatedActions) {
|
|
126
172
|
if (action.entry) {
|
|
127
|
-
const
|
|
128
|
-
|
|
173
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
174
|
+
{
|
|
175
|
+
contentType: action.contentType,
|
|
176
|
+
documentId: action.entryDocumentId,
|
|
177
|
+
locale: action.locale
|
|
178
|
+
},
|
|
179
|
+
{ strapi }
|
|
180
|
+
);
|
|
181
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
182
|
+
where: {
|
|
183
|
+
id: action.id
|
|
184
|
+
},
|
|
185
|
+
data: {
|
|
186
|
+
isEntryValid: isEntryValid2
|
|
187
|
+
}
|
|
129
188
|
});
|
|
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
189
|
}
|
|
142
190
|
}
|
|
143
191
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -181,24 +229,24 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
181
229
|
}
|
|
182
230
|
});
|
|
183
231
|
await async.map(actions, async (action) => {
|
|
184
|
-
if (action.entry && action.release) {
|
|
185
|
-
const
|
|
186
|
-
|
|
232
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
233
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
234
|
+
{
|
|
235
|
+
contentType: contentTypeUID,
|
|
236
|
+
documentId: action.entryDocumentId,
|
|
237
|
+
locale: action.locale
|
|
238
|
+
},
|
|
239
|
+
{ strapi }
|
|
240
|
+
);
|
|
241
|
+
releasesAffected.add(action.release.id);
|
|
242
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
243
|
+
where: {
|
|
244
|
+
id: action.id
|
|
245
|
+
},
|
|
246
|
+
data: {
|
|
247
|
+
isEntryValid: isEntryValid2
|
|
248
|
+
}
|
|
187
249
|
});
|
|
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
250
|
}
|
|
203
251
|
});
|
|
204
252
|
}
|
|
@@ -255,9 +303,38 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
255
303
|
}
|
|
256
304
|
}
|
|
257
305
|
}
|
|
306
|
+
const addEntryDocumentToReleaseActions = {
|
|
307
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
308
|
+
async up(trx, db) {
|
|
309
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
310
|
+
if (hasPolymorphicColumn) {
|
|
311
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
312
|
+
"strapi_release_actions",
|
|
313
|
+
"entry_document_id"
|
|
314
|
+
);
|
|
315
|
+
if (!hasEntryDocumentIdColumn) {
|
|
316
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
317
|
+
table.string("entry_document_id");
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
321
|
+
async.map(releaseActions, async (action) => {
|
|
322
|
+
const { target_type, target_id } = action;
|
|
323
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
324
|
+
if (entry) {
|
|
325
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
async down() {
|
|
331
|
+
throw new Error("not implemented");
|
|
332
|
+
}
|
|
333
|
+
};
|
|
258
334
|
const register = async ({ strapi: strapi2 }) => {
|
|
259
335
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
260
336
|
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
337
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
261
338
|
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
262
339
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
263
340
|
}
|
|
@@ -267,6 +344,104 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
267
344
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
268
345
|
}
|
|
269
346
|
};
|
|
347
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
348
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
349
|
+
where: {
|
|
350
|
+
actions: {
|
|
351
|
+
contentType,
|
|
352
|
+
entryDocumentId: entry.documentId,
|
|
353
|
+
locale: entry.locale
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
358
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
359
|
+
where: {
|
|
360
|
+
contentType,
|
|
361
|
+
entryDocumentId: entry.documentId,
|
|
362
|
+
locale: entry.locale
|
|
363
|
+
},
|
|
364
|
+
data: {
|
|
365
|
+
isEntryValid: entryStatus
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
for (const release2 of releases) {
|
|
369
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
373
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
374
|
+
where: {
|
|
375
|
+
actions: params
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
379
|
+
where: params
|
|
380
|
+
});
|
|
381
|
+
for (const release2 of releases) {
|
|
382
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
386
|
+
if (ctx.action !== "delete") {
|
|
387
|
+
return next();
|
|
388
|
+
}
|
|
389
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
390
|
+
return next();
|
|
391
|
+
}
|
|
392
|
+
const contentType = ctx.contentType.uid;
|
|
393
|
+
const { documentId, locale } = ctx.params;
|
|
394
|
+
const result = await next();
|
|
395
|
+
if (!result) {
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
400
|
+
contentType,
|
|
401
|
+
entryDocumentId: documentId,
|
|
402
|
+
...locale !== "*" && { locale }
|
|
403
|
+
});
|
|
404
|
+
} catch (error) {
|
|
405
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
406
|
+
error
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
};
|
|
411
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
412
|
+
if (ctx.action !== "update") {
|
|
413
|
+
return next();
|
|
414
|
+
}
|
|
415
|
+
if (!contentTypes$1.hasDraftAndPublish(ctx.contentType)) {
|
|
416
|
+
return next();
|
|
417
|
+
}
|
|
418
|
+
const contentType = ctx.contentType.uid;
|
|
419
|
+
const result = await next();
|
|
420
|
+
if (!result) {
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
427
|
+
error
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return result;
|
|
431
|
+
};
|
|
432
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
433
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
434
|
+
where: {
|
|
435
|
+
actions: params
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
439
|
+
where: params
|
|
440
|
+
});
|
|
441
|
+
for (const release2 of releases) {
|
|
442
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
270
445
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
271
446
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
272
447
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
@@ -274,115 +449,29 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
274
449
|
);
|
|
275
450
|
strapi2.db.lifecycles.subscribe({
|
|
276
451
|
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
452
|
/**
|
|
305
|
-
* deleteMany
|
|
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
|
-
/**
|
|
317
|
-
* We delete the release actions related to deleted entries
|
|
318
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
453
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
319
454
|
*/
|
|
320
455
|
async afterDeleteMany(event) {
|
|
321
456
|
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
|
-
}
|
|
457
|
+
const model = strapi2.getModel(event.model.uid);
|
|
458
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
459
|
+
const { where } = event.params;
|
|
460
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
461
|
+
contentType: model.uid,
|
|
462
|
+
locale: where.locale ?? null,
|
|
463
|
+
...where.documentId && { entryDocumentId: where.documentId }
|
|
342
464
|
});
|
|
343
|
-
for (const release2 of releases) {
|
|
344
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
345
|
-
}
|
|
346
465
|
}
|
|
347
466
|
} catch (error) {
|
|
348
467
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
349
468
|
error
|
|
350
469
|
});
|
|
351
470
|
}
|
|
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
471
|
}
|
|
385
472
|
});
|
|
473
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
474
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
386
475
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
387
476
|
strapi2.log.error(
|
|
388
477
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -474,15 +563,13 @@ const schema = {
|
|
|
474
563
|
enum: ["publish", "unpublish"],
|
|
475
564
|
required: true
|
|
476
565
|
},
|
|
477
|
-
entry: {
|
|
478
|
-
type: "relation",
|
|
479
|
-
relation: "morphToOne",
|
|
480
|
-
configurable: false
|
|
481
|
-
},
|
|
482
566
|
contentType: {
|
|
483
567
|
type: "string",
|
|
484
568
|
required: true
|
|
485
569
|
},
|
|
570
|
+
entryDocumentId: {
|
|
571
|
+
type: "string"
|
|
572
|
+
},
|
|
486
573
|
locale: {
|
|
487
574
|
type: "string"
|
|
488
575
|
},
|
|
@@ -504,18 +591,6 @@ const contentTypes = {
|
|
|
504
591
|
release: release$1,
|
|
505
592
|
"release-action": releaseAction$1
|
|
506
593
|
};
|
|
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
594
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
520
595
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
521
596
|
strapi2.eventHub.emit(event, {
|
|
@@ -524,93 +599,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
524
599
|
release: release2
|
|
525
600
|
});
|
|
526
601
|
};
|
|
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
602
|
const getFormattedActions = async (releaseId) => {
|
|
574
603
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
575
604
|
where: {
|
|
576
605
|
release: {
|
|
577
606
|
id: releaseId
|
|
578
607
|
}
|
|
579
|
-
},
|
|
580
|
-
populate: {
|
|
581
|
-
entry: {
|
|
582
|
-
fields: ["id"]
|
|
583
|
-
}
|
|
584
608
|
}
|
|
585
609
|
});
|
|
586
610
|
if (actions.length === 0) {
|
|
587
611
|
throw new errors.ValidationError("No entries to publish");
|
|
588
612
|
}
|
|
589
|
-
const
|
|
590
|
-
const singleTypeActions = [];
|
|
613
|
+
const formattedActions = {};
|
|
591
614
|
for (const action of actions) {
|
|
592
615
|
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
|
-
});
|
|
616
|
+
if (!formattedActions[contentTypeUid]) {
|
|
617
|
+
formattedActions[contentTypeUid] = {
|
|
618
|
+
publish: [],
|
|
619
|
+
unpublish: []
|
|
620
|
+
};
|
|
611
621
|
}
|
|
622
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
623
|
+
documentId: action.entryDocumentId,
|
|
624
|
+
locale: action.locale
|
|
625
|
+
});
|
|
612
626
|
}
|
|
613
|
-
return
|
|
627
|
+
return formattedActions;
|
|
614
628
|
};
|
|
615
629
|
return {
|
|
616
630
|
async create(releaseData, { user }) {
|
|
@@ -657,91 +671,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
657
671
|
}
|
|
658
672
|
});
|
|
659
673
|
},
|
|
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;
|
|
674
|
+
findMany(query) {
|
|
675
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
676
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
677
|
+
...dbQuery
|
|
745
678
|
});
|
|
746
679
|
},
|
|
747
680
|
async update(id, releaseData, { user }) {
|
|
@@ -777,12 +710,208 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
777
710
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
778
711
|
return updatedRelease;
|
|
779
712
|
},
|
|
780
|
-
async
|
|
781
|
-
const
|
|
713
|
+
async getAllComponents() {
|
|
714
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
715
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
716
|
+
const componentsMap = components.reduce(
|
|
717
|
+
(acc, component) => {
|
|
718
|
+
acc[component.uid] = component;
|
|
719
|
+
return acc;
|
|
720
|
+
},
|
|
721
|
+
{}
|
|
722
|
+
);
|
|
723
|
+
return componentsMap;
|
|
724
|
+
},
|
|
725
|
+
async delete(releaseId) {
|
|
726
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
727
|
+
where: { id: releaseId },
|
|
728
|
+
populate: {
|
|
729
|
+
actions: {
|
|
730
|
+
select: ["id"]
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
if (!release2) {
|
|
735
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
736
|
+
}
|
|
737
|
+
if (release2.releasedAt) {
|
|
738
|
+
throw new errors.ValidationError("Release already published");
|
|
739
|
+
}
|
|
740
|
+
await strapi2.db.transaction(async () => {
|
|
741
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
742
|
+
where: {
|
|
743
|
+
id: {
|
|
744
|
+
$in: release2.actions.map((action) => action.id)
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
749
|
+
where: {
|
|
750
|
+
id: releaseId
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
if (release2.scheduledAt) {
|
|
755
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
756
|
+
await schedulingService.cancel(release2.id);
|
|
757
|
+
}
|
|
758
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
759
|
+
return release2;
|
|
760
|
+
},
|
|
761
|
+
async publish(releaseId) {
|
|
762
|
+
const {
|
|
763
|
+
release: release2,
|
|
764
|
+
error
|
|
765
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
766
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
767
|
+
if (!lockedRelease) {
|
|
768
|
+
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
769
|
+
}
|
|
770
|
+
if (lockedRelease.releasedAt) {
|
|
771
|
+
throw new errors.ValidationError("Release already published");
|
|
772
|
+
}
|
|
773
|
+
if (lockedRelease.status === "failed") {
|
|
774
|
+
throw new errors.ValidationError("Release failed to publish");
|
|
775
|
+
}
|
|
776
|
+
try {
|
|
777
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
778
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
779
|
+
await strapi2.db.transaction(
|
|
780
|
+
async () => Promise.all(
|
|
781
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
782
|
+
const contentType = contentTypeUid;
|
|
783
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
784
|
+
return Promise.all([
|
|
785
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
786
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
787
|
+
]);
|
|
788
|
+
})
|
|
789
|
+
)
|
|
790
|
+
);
|
|
791
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
792
|
+
where: {
|
|
793
|
+
id: releaseId
|
|
794
|
+
},
|
|
795
|
+
data: {
|
|
796
|
+
status: "done",
|
|
797
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
801
|
+
isPublished: true,
|
|
802
|
+
release: release22
|
|
803
|
+
});
|
|
804
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
805
|
+
return { release: release22, error: null };
|
|
806
|
+
} catch (error2) {
|
|
807
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
808
|
+
isPublished: false,
|
|
809
|
+
error: error2
|
|
810
|
+
});
|
|
811
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
812
|
+
status: "failed"
|
|
813
|
+
}).transacting(trx).execute();
|
|
814
|
+
return {
|
|
815
|
+
release: null,
|
|
816
|
+
error: error2
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
if (error instanceof Error) {
|
|
821
|
+
throw error;
|
|
822
|
+
}
|
|
823
|
+
return release2;
|
|
824
|
+
},
|
|
825
|
+
async updateReleaseStatus(releaseId) {
|
|
826
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
827
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
828
|
+
releaseActionService.countActions({
|
|
829
|
+
filters: {
|
|
830
|
+
release: releaseId
|
|
831
|
+
}
|
|
832
|
+
}),
|
|
833
|
+
releaseActionService.countActions({
|
|
834
|
+
filters: {
|
|
835
|
+
release: releaseId,
|
|
836
|
+
isEntryValid: false
|
|
837
|
+
}
|
|
838
|
+
})
|
|
839
|
+
]);
|
|
840
|
+
if (totalActions > 0) {
|
|
841
|
+
if (invalidActions > 0) {
|
|
842
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
843
|
+
where: {
|
|
844
|
+
id: releaseId
|
|
845
|
+
},
|
|
846
|
+
data: {
|
|
847
|
+
status: "blocked"
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
852
|
+
where: {
|
|
853
|
+
id: releaseId
|
|
854
|
+
},
|
|
855
|
+
data: {
|
|
856
|
+
status: "ready"
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
861
|
+
where: {
|
|
862
|
+
id: releaseId
|
|
863
|
+
},
|
|
864
|
+
data: {
|
|
865
|
+
status: "empty"
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
};
|
|
871
|
+
const getGroupName = (queryValue) => {
|
|
872
|
+
switch (queryValue) {
|
|
873
|
+
case "contentType":
|
|
874
|
+
return "contentType.displayName";
|
|
875
|
+
case "type":
|
|
876
|
+
return "type";
|
|
877
|
+
case "locale":
|
|
878
|
+
return _.getOr("No locale", "locale.name");
|
|
879
|
+
default:
|
|
880
|
+
return "contentType.displayName";
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
884
|
+
const getLocalesDataForActions = async () => {
|
|
885
|
+
if (!strapi2.plugin("i18n")) {
|
|
886
|
+
return {};
|
|
887
|
+
}
|
|
888
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
889
|
+
return allLocales.reduce((acc, locale) => {
|
|
890
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
891
|
+
return acc;
|
|
892
|
+
}, {});
|
|
893
|
+
};
|
|
894
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
895
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
896
|
+
const contentTypesData = {};
|
|
897
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
898
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
899
|
+
uid: contentTypeUid
|
|
900
|
+
});
|
|
901
|
+
contentTypesData[contentTypeUid] = {
|
|
902
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
903
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
return contentTypesData;
|
|
907
|
+
};
|
|
908
|
+
return {
|
|
909
|
+
async create(releaseId, action) {
|
|
910
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
782
911
|
strapi: strapi2
|
|
783
912
|
});
|
|
784
913
|
await Promise.all([
|
|
785
|
-
|
|
914
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
786
915
|
validateUniqueEntry(releaseId, action)
|
|
787
916
|
]);
|
|
788
917
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
@@ -792,28 +921,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
792
921
|
if (release2.releasedAt) {
|
|
793
922
|
throw new errors.ValidationError("Release already published");
|
|
794
923
|
}
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
924
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
925
|
+
{
|
|
926
|
+
contentType: action.contentType,
|
|
927
|
+
documentId: action.entryDocumentId,
|
|
928
|
+
locale: action.locale
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
strapi: strapi2
|
|
932
|
+
}
|
|
933
|
+
) : true;
|
|
798
934
|
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
799
935
|
data: {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
isEntryValid,
|
|
804
|
-
entry: {
|
|
805
|
-
id: entry.id,
|
|
806
|
-
__type: entry.contentType,
|
|
807
|
-
__pivot: { field: "entry" }
|
|
808
|
-
},
|
|
809
|
-
release: releaseId
|
|
936
|
+
...action,
|
|
937
|
+
release: release2.id,
|
|
938
|
+
isEntryValid: actionStatus
|
|
810
939
|
},
|
|
811
|
-
populate: { release: { select: ["id"] }
|
|
940
|
+
populate: { release: { select: ["id"] } }
|
|
812
941
|
});
|
|
813
|
-
|
|
942
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
814
943
|
return releaseAction2;
|
|
815
944
|
},
|
|
816
|
-
async
|
|
945
|
+
async findPage(releaseId, query) {
|
|
817
946
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
818
947
|
where: { id: releaseId },
|
|
819
948
|
select: ["id"]
|
|
@@ -822,21 +951,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
822
951
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
823
952
|
}
|
|
824
953
|
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
825
|
-
|
|
954
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
826
955
|
...dbQuery,
|
|
827
|
-
populate: {
|
|
828
|
-
entry: {
|
|
829
|
-
populate: "*"
|
|
830
|
-
}
|
|
831
|
-
},
|
|
832
956
|
where: {
|
|
833
957
|
release: releaseId
|
|
834
958
|
}
|
|
835
959
|
});
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
960
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
961
|
+
const actionsWithEntry = await async.map(actions, async (action) => {
|
|
962
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
963
|
+
const entry = await getEntry(
|
|
964
|
+
{
|
|
965
|
+
contentType: action.contentType,
|
|
966
|
+
documentId: action.entryDocumentId,
|
|
967
|
+
locale: action.locale,
|
|
968
|
+
populate,
|
|
969
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
970
|
+
},
|
|
971
|
+
{ strapi: strapi2 }
|
|
972
|
+
);
|
|
973
|
+
return {
|
|
974
|
+
...action,
|
|
975
|
+
entry,
|
|
976
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
977
|
+
};
|
|
978
|
+
});
|
|
979
|
+
return {
|
|
980
|
+
results: actionsWithEntry,
|
|
981
|
+
pagination
|
|
982
|
+
};
|
|
840
983
|
},
|
|
841
984
|
async groupActions(actions, groupBy) {
|
|
842
985
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -845,8 +988,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
845
988
|
}
|
|
846
989
|
return acc;
|
|
847
990
|
}, []);
|
|
848
|
-
const allReleaseContentTypesDictionary = await
|
|
849
|
-
const allLocalesDictionary = await
|
|
991
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
992
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
850
993
|
const formattedData = actions.map((action) => {
|
|
851
994
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
852
995
|
return {
|
|
@@ -857,165 +1000,58 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
857
1000
|
mainFieldValue: action.entry[mainField],
|
|
858
1001
|
uid: action.contentType
|
|
859
1002
|
}
|
|
860
|
-
};
|
|
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
|
-
});
|
|
1003
|
+
};
|
|
945
1004
|
});
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
await schedulingService.cancel(release2.id);
|
|
949
|
-
}
|
|
950
|
-
strapi2.telemetry.send("didDeleteContentRelease");
|
|
951
|
-
return release2;
|
|
1005
|
+
const groupName = getGroupName(groupBy);
|
|
1006
|
+
return _.groupBy(groupName)(formattedData);
|
|
952
1007
|
},
|
|
953
|
-
|
|
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");
|
|
1008
|
+
getContentTypeModelsFromActions(actions) {
|
|
1009
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1010
|
+
if (!acc.includes(action.contentType)) {
|
|
1011
|
+
acc.push(action.contentType);
|
|
967
1012
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1013
|
+
return acc;
|
|
1014
|
+
}, []);
|
|
1015
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1016
|
+
(acc, contentTypeUid) => {
|
|
1017
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1018
|
+
return acc;
|
|
1019
|
+
},
|
|
1020
|
+
{}
|
|
1021
|
+
);
|
|
1022
|
+
return contentTypeModelsMap;
|
|
1023
|
+
},
|
|
1024
|
+
async countActions(query) {
|
|
1025
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1026
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1027
|
+
},
|
|
1028
|
+
async update(actionId, releaseId, update) {
|
|
1029
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1030
|
+
where: {
|
|
1031
|
+
id: actionId,
|
|
1032
|
+
release: {
|
|
1033
|
+
id: releaseId,
|
|
1034
|
+
releasedAt: {
|
|
1035
|
+
$null: true
|
|
991
1036
|
}
|
|
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
|
|
1003
|
-
});
|
|
1004
|
-
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
1005
|
-
status: "failed"
|
|
1006
|
-
}).transacting(trx).execute();
|
|
1007
|
-
return {
|
|
1008
|
-
release: null,
|
|
1009
|
-
error: error2
|
|
1010
|
-
};
|
|
1037
|
+
}
|
|
1011
1038
|
}
|
|
1012
1039
|
});
|
|
1013
|
-
if (
|
|
1014
|
-
throw
|
|
1040
|
+
if (!action) {
|
|
1041
|
+
throw new errors.NotFoundError(
|
|
1042
|
+
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1043
|
+
);
|
|
1015
1044
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1045
|
+
const actionStatus = update.type === "publish" ? getDraftEntryValidStatus(
|
|
1046
|
+
{
|
|
1047
|
+
contentType: action.contentType,
|
|
1048
|
+
documentId: action.entryDocumentId,
|
|
1049
|
+
locale: action.locale
|
|
1050
|
+
},
|
|
1051
|
+
{
|
|
1052
|
+
strapi: strapi2
|
|
1053
|
+
}
|
|
1054
|
+
) : true;
|
|
1019
1055
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1020
1056
|
where: {
|
|
1021
1057
|
id: actionId,
|
|
@@ -1026,16 +1062,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1026
1062
|
}
|
|
1027
1063
|
}
|
|
1028
1064
|
},
|
|
1029
|
-
data:
|
|
1065
|
+
data: {
|
|
1066
|
+
...update,
|
|
1067
|
+
isEntryValid: actionStatus
|
|
1068
|
+
}
|
|
1030
1069
|
});
|
|
1031
|
-
|
|
1032
|
-
throw new errors.NotFoundError(
|
|
1033
|
-
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1034
|
-
);
|
|
1035
|
-
}
|
|
1070
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1036
1071
|
return updatedAction;
|
|
1037
1072
|
},
|
|
1038
|
-
async
|
|
1073
|
+
async delete(actionId, releaseId) {
|
|
1039
1074
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1040
1075
|
where: {
|
|
1041
1076
|
id: actionId,
|
|
@@ -1052,51 +1087,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1052
1087
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1053
1088
|
);
|
|
1054
1089
|
}
|
|
1055
|
-
|
|
1090
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1056
1091
|
return deletedAction;
|
|
1057
|
-
},
|
|
1058
|
-
async updateReleaseStatus(releaseId) {
|
|
1059
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
1060
|
-
this.countActions({
|
|
1061
|
-
filters: {
|
|
1062
|
-
release: releaseId
|
|
1063
|
-
}
|
|
1064
|
-
}),
|
|
1065
|
-
this.countActions({
|
|
1066
|
-
filters: {
|
|
1067
|
-
release: releaseId,
|
|
1068
|
-
isEntryValid: false
|
|
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"
|
|
1080
|
-
}
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1084
|
-
where: {
|
|
1085
|
-
id: releaseId
|
|
1086
|
-
},
|
|
1087
|
-
data: {
|
|
1088
|
-
status: "ready"
|
|
1089
|
-
}
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1093
|
-
where: {
|
|
1094
|
-
id: releaseId
|
|
1095
|
-
},
|
|
1096
|
-
data: {
|
|
1097
|
-
status: "empty"
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
1092
|
}
|
|
1101
1093
|
};
|
|
1102
1094
|
};
|
|
@@ -1112,30 +1104,35 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1112
1104
|
where: {
|
|
1113
1105
|
id: releaseId
|
|
1114
1106
|
},
|
|
1115
|
-
populate: {
|
|
1107
|
+
populate: {
|
|
1108
|
+
actions: true
|
|
1109
|
+
}
|
|
1116
1110
|
});
|
|
1117
1111
|
if (!release2) {
|
|
1118
1112
|
throw new errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1119
1113
|
}
|
|
1120
1114
|
const isEntryInRelease = release2.actions.some(
|
|
1121
|
-
(action) =>
|
|
1115
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1122
1116
|
);
|
|
1123
1117
|
if (isEntryInRelease) {
|
|
1124
1118
|
throw new AlreadyOnReleaseError(
|
|
1125
|
-
`Entry with
|
|
1119
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1126
1120
|
);
|
|
1127
1121
|
}
|
|
1128
1122
|
},
|
|
1129
|
-
|
|
1123
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1130
1124
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1131
1125
|
if (!contentType) {
|
|
1132
1126
|
throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1133
1127
|
}
|
|
1134
|
-
if (!contentType
|
|
1128
|
+
if (!contentTypes$1.hasDraftAndPublish(contentType)) {
|
|
1135
1129
|
throw new errors.ValidationError(
|
|
1136
1130
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1137
1131
|
);
|
|
1138
1132
|
}
|
|
1133
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1134
|
+
throw new errors.ValidationError("Document id is required for collection type");
|
|
1135
|
+
}
|
|
1139
1136
|
},
|
|
1140
1137
|
async validatePendingReleasesLimit() {
|
|
1141
1138
|
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
@@ -1224,78 +1221,152 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1224
1221
|
}
|
|
1225
1222
|
};
|
|
1226
1223
|
};
|
|
1224
|
+
const DEFAULT_SETTINGS = {
|
|
1225
|
+
defaultTimezone: null
|
|
1226
|
+
};
|
|
1227
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1228
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1229
|
+
return {
|
|
1230
|
+
async update({ settings: settings2 }) {
|
|
1231
|
+
const store = await getStore();
|
|
1232
|
+
store.set({ key: "settings", value: settings2 });
|
|
1233
|
+
return settings2;
|
|
1234
|
+
},
|
|
1235
|
+
async find() {
|
|
1236
|
+
const store = await getStore();
|
|
1237
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1238
|
+
return {
|
|
1239
|
+
...DEFAULT_SETTINGS,
|
|
1240
|
+
...settings2 || {}
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
};
|
|
1227
1245
|
const services = {
|
|
1228
1246
|
release: createReleaseService,
|
|
1247
|
+
"release-action": createReleaseActionService,
|
|
1229
1248
|
"release-validation": createReleaseValidationService,
|
|
1230
|
-
scheduling: createSchedulingService
|
|
1249
|
+
scheduling: createSchedulingService,
|
|
1250
|
+
settings: createSettingsService
|
|
1231
1251
|
};
|
|
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()
|
|
1252
|
+
const RELEASE_SCHEMA = yup$1.object().shape({
|
|
1253
|
+
name: yup$1.string().trim().required(),
|
|
1254
|
+
scheduledAt: yup$1.string().nullable(),
|
|
1255
|
+
timezone: yup$1.string().when("scheduledAt", {
|
|
1256
|
+
is: (value) => value !== null && value !== void 0,
|
|
1257
|
+
then: yup$1.string().required(),
|
|
1258
|
+
otherwise: yup$1.string().nullable()
|
|
1250
1259
|
})
|
|
1251
1260
|
}).required().noUnknown();
|
|
1261
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = yup$1.object().shape({
|
|
1262
|
+
contentType: yup$1.string().required(),
|
|
1263
|
+
entryDocumentId: yup$1.string().nullable(),
|
|
1264
|
+
hasEntryAttached: yup$1.string().nullable(),
|
|
1265
|
+
locale: yup$1.string().nullable()
|
|
1266
|
+
}).required().noUnknown();
|
|
1252
1267
|
const validateRelease = validateYupSchema(RELEASE_SCHEMA);
|
|
1268
|
+
const validatefindByDocumentAttachedParams = validateYupSchema(
|
|
1269
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1270
|
+
);
|
|
1253
1271
|
const releaseController = {
|
|
1254
|
-
|
|
1272
|
+
/**
|
|
1273
|
+
* Find releases based on documents attached or not to the release.
|
|
1274
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1275
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1276
|
+
*/
|
|
1277
|
+
async findByDocumentAttached(ctx) {
|
|
1255
1278
|
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1256
1279
|
ability: ctx.state.userAbility,
|
|
1257
1280
|
model: RELEASE_MODEL_UID
|
|
1258
1281
|
});
|
|
1259
1282
|
await permissionsManager.validateQuery(ctx.query);
|
|
1260
1283
|
const releaseService = getService("release", { strapi });
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
const
|
|
1267
|
-
|
|
1268
|
-
|
|
1284
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1285
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1286
|
+
const { contentType, entryDocumentId, hasEntryAttached, locale } = query;
|
|
1287
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1288
|
+
if (isEntryAttached) {
|
|
1289
|
+
const releases = await releaseService.findMany({
|
|
1290
|
+
where: {
|
|
1291
|
+
releasedAt: null,
|
|
1292
|
+
actions: {
|
|
1293
|
+
contentType,
|
|
1294
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1295
|
+
locale: locale ?? null
|
|
1296
|
+
}
|
|
1297
|
+
},
|
|
1298
|
+
populate: {
|
|
1299
|
+
actions: {
|
|
1300
|
+
fields: ["type"]
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1304
|
+
ctx.body = { data: releases };
|
|
1269
1305
|
} else {
|
|
1270
|
-
const
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
const { actions, ...releaseData } = release2;
|
|
1274
|
-
return {
|
|
1275
|
-
...releaseData,
|
|
1306
|
+
const relatedReleases = await releaseService.findMany({
|
|
1307
|
+
where: {
|
|
1308
|
+
releasedAt: null,
|
|
1276
1309
|
actions: {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1310
|
+
contentType,
|
|
1311
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1312
|
+
locale: locale ?? null
|
|
1280
1313
|
}
|
|
1281
|
-
}
|
|
1314
|
+
}
|
|
1282
1315
|
});
|
|
1283
|
-
const
|
|
1316
|
+
const releases = await releaseService.findMany({
|
|
1284
1317
|
where: {
|
|
1318
|
+
$or: [
|
|
1319
|
+
{
|
|
1320
|
+
id: {
|
|
1321
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
actions: null
|
|
1326
|
+
}
|
|
1327
|
+
],
|
|
1285
1328
|
releasedAt: null
|
|
1286
1329
|
}
|
|
1287
1330
|
});
|
|
1288
|
-
ctx.body = { data
|
|
1331
|
+
ctx.body = { data: releases };
|
|
1289
1332
|
}
|
|
1290
1333
|
},
|
|
1334
|
+
async findPage(ctx) {
|
|
1335
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1336
|
+
ability: ctx.state.userAbility,
|
|
1337
|
+
model: RELEASE_MODEL_UID
|
|
1338
|
+
});
|
|
1339
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1340
|
+
const releaseService = getService("release", { strapi });
|
|
1341
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1342
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1343
|
+
const data = results.map((release2) => {
|
|
1344
|
+
const { actions, ...releaseData } = release2;
|
|
1345
|
+
return {
|
|
1346
|
+
...releaseData,
|
|
1347
|
+
actions: {
|
|
1348
|
+
meta: {
|
|
1349
|
+
count: actions.count
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
});
|
|
1354
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1355
|
+
where: {
|
|
1356
|
+
releasedAt: null
|
|
1357
|
+
}
|
|
1358
|
+
});
|
|
1359
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1360
|
+
},
|
|
1291
1361
|
async findOne(ctx) {
|
|
1292
1362
|
const id = ctx.params.id;
|
|
1293
1363
|
const releaseService = getService("release", { strapi });
|
|
1364
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1294
1365
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1295
1366
|
if (!release2) {
|
|
1296
1367
|
throw new errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1297
1368
|
}
|
|
1298
|
-
const count = await
|
|
1369
|
+
const count = await releaseActionService.countActions({
|
|
1299
1370
|
filters: {
|
|
1300
1371
|
release: id
|
|
1301
1372
|
}
|
|
@@ -1315,28 +1386,43 @@ const releaseController = {
|
|
|
1315
1386
|
ctx.body = { data };
|
|
1316
1387
|
},
|
|
1317
1388
|
async mapEntriesToReleases(ctx) {
|
|
1318
|
-
const { contentTypeUid,
|
|
1319
|
-
if (!contentTypeUid || !
|
|
1389
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1390
|
+
if (!contentTypeUid || !documentIds) {
|
|
1320
1391
|
throw new errors.ValidationError("Missing required query parameters");
|
|
1321
1392
|
}
|
|
1322
1393
|
const releaseService = getService("release", { strapi });
|
|
1323
|
-
const releasesWithActions = await releaseService.
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1394
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1395
|
+
where: {
|
|
1396
|
+
releasedAt: null,
|
|
1397
|
+
actions: {
|
|
1398
|
+
contentType: contentTypeUid,
|
|
1399
|
+
entryDocumentId: {
|
|
1400
|
+
$in: documentIds
|
|
1401
|
+
},
|
|
1402
|
+
locale
|
|
1403
|
+
}
|
|
1404
|
+
},
|
|
1405
|
+
populate: {
|
|
1406
|
+
actions: true
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1327
1409
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1328
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1329
1410
|
(acc, release2) => {
|
|
1330
1411
|
release2.actions.forEach((action) => {
|
|
1331
|
-
if (
|
|
1332
|
-
|
|
1412
|
+
if (action.contentType !== contentTypeUid) {
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
if (locale && action.locale !== locale) {
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
if (!acc[action.entryDocumentId]) {
|
|
1419
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1333
1420
|
} else {
|
|
1334
|
-
acc[action.
|
|
1421
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1335
1422
|
}
|
|
1336
1423
|
});
|
|
1337
1424
|
return acc;
|
|
1338
1425
|
},
|
|
1339
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1340
1426
|
{}
|
|
1341
1427
|
);
|
|
1342
1428
|
ctx.body = {
|
|
@@ -1381,18 +1467,18 @@ const releaseController = {
|
|
|
1381
1467
|
};
|
|
1382
1468
|
},
|
|
1383
1469
|
async publish(ctx) {
|
|
1384
|
-
const user = ctx.state.user;
|
|
1385
1470
|
const id = ctx.params.id;
|
|
1386
1471
|
const releaseService = getService("release", { strapi });
|
|
1387
|
-
const
|
|
1472
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1473
|
+
const release2 = await releaseService.publish(id);
|
|
1388
1474
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1389
|
-
|
|
1475
|
+
releaseActionService.countActions({
|
|
1390
1476
|
filters: {
|
|
1391
1477
|
release: id,
|
|
1392
1478
|
type: "publish"
|
|
1393
1479
|
}
|
|
1394
1480
|
}),
|
|
1395
|
-
|
|
1481
|
+
releaseActionService.countActions({
|
|
1396
1482
|
filters: {
|
|
1397
1483
|
release: id,
|
|
1398
1484
|
type: "unpublish"
|
|
@@ -1410,24 +1496,27 @@ const releaseController = {
|
|
|
1410
1496
|
}
|
|
1411
1497
|
};
|
|
1412
1498
|
const RELEASE_ACTION_SCHEMA = yup$1.object().shape({
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
}).required(),
|
|
1499
|
+
contentType: yup$1.string().required(),
|
|
1500
|
+
entryDocumentId: yup$1.strapiID(),
|
|
1501
|
+
locale: yup$1.string(),
|
|
1417
1502
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1418
1503
|
});
|
|
1419
1504
|
const RELEASE_ACTION_UPDATE_SCHEMA = yup$1.object().shape({
|
|
1420
1505
|
type: yup$1.string().oneOf(["publish", "unpublish"]).required()
|
|
1421
1506
|
});
|
|
1507
|
+
const FIND_MANY_ACTIONS_PARAMS = yup$1.object().shape({
|
|
1508
|
+
groupBy: yup$1.string().oneOf(["action", "contentType", "locale"])
|
|
1509
|
+
});
|
|
1422
1510
|
const validateReleaseAction = validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1423
1511
|
const validateReleaseActionUpdateSchema = validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1512
|
+
const validateFindManyActionsParams = validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1424
1513
|
const releaseActionController = {
|
|
1425
1514
|
async create(ctx) {
|
|
1426
1515
|
const releaseId = ctx.params.releaseId;
|
|
1427
1516
|
const releaseActionArgs = ctx.request.body;
|
|
1428
1517
|
await validateReleaseAction(releaseActionArgs);
|
|
1429
|
-
const
|
|
1430
|
-
const releaseAction2 = await
|
|
1518
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1519
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1431
1520
|
ctx.created({
|
|
1432
1521
|
data: releaseAction2
|
|
1433
1522
|
});
|
|
@@ -1438,12 +1527,12 @@ const releaseActionController = {
|
|
|
1438
1527
|
await Promise.all(
|
|
1439
1528
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1440
1529
|
);
|
|
1441
|
-
const
|
|
1530
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1442
1531
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1443
1532
|
const releaseActions2 = await Promise.all(
|
|
1444
1533
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1445
1534
|
try {
|
|
1446
|
-
const action = await
|
|
1535
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1447
1536
|
return action;
|
|
1448
1537
|
} catch (error) {
|
|
1449
1538
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1470,10 +1559,17 @@ const releaseActionController = {
|
|
|
1470
1559
|
ability: ctx.state.userAbility,
|
|
1471
1560
|
model: RELEASE_ACTION_MODEL_UID
|
|
1472
1561
|
});
|
|
1562
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1563
|
+
if (ctx.query.groupBy) {
|
|
1564
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1565
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1569
|
+
delete ctx.query.groupBy;
|
|
1473
1570
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1474
|
-
const
|
|
1475
|
-
const { results, pagination } = await
|
|
1476
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1571
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1572
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1477
1573
|
...query
|
|
1478
1574
|
});
|
|
1479
1575
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
@@ -1489,10 +1585,11 @@ const releaseActionController = {
|
|
|
1489
1585
|
}, {});
|
|
1490
1586
|
const sanitizedResults = await async.map(results, async (action) => ({
|
|
1491
1587
|
...action,
|
|
1492
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1588
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1493
1589
|
}));
|
|
1494
|
-
const groupedData = await
|
|
1495
|
-
const contentTypes2 =
|
|
1590
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1591
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1592
|
+
const releaseService = getService("release", { strapi });
|
|
1496
1593
|
const components = await releaseService.getAllComponents();
|
|
1497
1594
|
ctx.body = {
|
|
1498
1595
|
data: groupedData,
|
|
@@ -1508,8 +1605,8 @@ const releaseActionController = {
|
|
|
1508
1605
|
const releaseId = ctx.params.releaseId;
|
|
1509
1606
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1510
1607
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1511
|
-
const
|
|
1512
|
-
const updatedAction = await
|
|
1608
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1609
|
+
const updatedAction = await releaseActionService.update(
|
|
1513
1610
|
actionId,
|
|
1514
1611
|
releaseId,
|
|
1515
1612
|
releaseActionUpdateArgs
|
|
@@ -1521,14 +1618,36 @@ const releaseActionController = {
|
|
|
1521
1618
|
async delete(ctx) {
|
|
1522
1619
|
const actionId = ctx.params.actionId;
|
|
1523
1620
|
const releaseId = ctx.params.releaseId;
|
|
1524
|
-
const
|
|
1525
|
-
const deletedReleaseAction = await
|
|
1621
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1622
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1526
1623
|
ctx.body = {
|
|
1527
1624
|
data: deletedReleaseAction
|
|
1528
1625
|
};
|
|
1529
1626
|
}
|
|
1530
1627
|
};
|
|
1531
|
-
const
|
|
1628
|
+
const SETTINGS_SCHEMA = yup.object().shape({
|
|
1629
|
+
defaultTimezone: yup.string().nullable().default(null)
|
|
1630
|
+
}).required().noUnknown();
|
|
1631
|
+
const validateSettings = validateYupSchema(SETTINGS_SCHEMA);
|
|
1632
|
+
const settingsController = {
|
|
1633
|
+
async find(ctx) {
|
|
1634
|
+
const settingsService = getService("settings", { strapi });
|
|
1635
|
+
const settings2 = await settingsService.find();
|
|
1636
|
+
ctx.body = { data: settings2 };
|
|
1637
|
+
},
|
|
1638
|
+
async update(ctx) {
|
|
1639
|
+
const settingsBody = ctx.request.body;
|
|
1640
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1641
|
+
const settingsService = getService("settings", { strapi });
|
|
1642
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1643
|
+
ctx.body = { data: updatedSettings };
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
const controllers = {
|
|
1647
|
+
release: releaseController,
|
|
1648
|
+
"release-action": releaseActionController,
|
|
1649
|
+
settings: settingsController
|
|
1650
|
+
};
|
|
1532
1651
|
const release = {
|
|
1533
1652
|
type: "admin",
|
|
1534
1653
|
routes: [
|
|
@@ -1548,6 +1667,22 @@ const release = {
|
|
|
1548
1667
|
]
|
|
1549
1668
|
}
|
|
1550
1669
|
},
|
|
1670
|
+
{
|
|
1671
|
+
method: "GET",
|
|
1672
|
+
path: "/getByDocumentAttached",
|
|
1673
|
+
handler: "release.findByDocumentAttached",
|
|
1674
|
+
config: {
|
|
1675
|
+
policies: [
|
|
1676
|
+
"admin::isAuthenticatedAdmin",
|
|
1677
|
+
{
|
|
1678
|
+
name: "admin::hasPermissions",
|
|
1679
|
+
config: {
|
|
1680
|
+
actions: ["plugin::content-releases.read"]
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
]
|
|
1684
|
+
}
|
|
1685
|
+
},
|
|
1551
1686
|
{
|
|
1552
1687
|
method: "POST",
|
|
1553
1688
|
path: "/",
|
|
@@ -1567,7 +1702,7 @@ const release = {
|
|
|
1567
1702
|
{
|
|
1568
1703
|
method: "GET",
|
|
1569
1704
|
path: "/",
|
|
1570
|
-
handler: "release.
|
|
1705
|
+
handler: "release.findPage",
|
|
1571
1706
|
config: {
|
|
1572
1707
|
policies: [
|
|
1573
1708
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1731,7 +1866,45 @@ const releaseAction = {
|
|
|
1731
1866
|
}
|
|
1732
1867
|
]
|
|
1733
1868
|
};
|
|
1869
|
+
const settings = {
|
|
1870
|
+
type: "admin",
|
|
1871
|
+
routes: [
|
|
1872
|
+
{
|
|
1873
|
+
method: "GET",
|
|
1874
|
+
path: "/settings",
|
|
1875
|
+
handler: "settings.find",
|
|
1876
|
+
config: {
|
|
1877
|
+
policies: [
|
|
1878
|
+
"admin::isAuthenticatedAdmin",
|
|
1879
|
+
{
|
|
1880
|
+
name: "admin::hasPermissions",
|
|
1881
|
+
config: {
|
|
1882
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
]
|
|
1886
|
+
}
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
method: "PUT",
|
|
1890
|
+
path: "/settings",
|
|
1891
|
+
handler: "settings.update",
|
|
1892
|
+
config: {
|
|
1893
|
+
policies: [
|
|
1894
|
+
"admin::isAuthenticatedAdmin",
|
|
1895
|
+
{
|
|
1896
|
+
name: "admin::hasPermissions",
|
|
1897
|
+
config: {
|
|
1898
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
]
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
]
|
|
1905
|
+
};
|
|
1734
1906
|
const routes = {
|
|
1907
|
+
settings,
|
|
1735
1908
|
release,
|
|
1736
1909
|
"release-action": releaseAction
|
|
1737
1910
|
};
|