@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.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),
|
|
@@ -102,6 +116,38 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 }) =
|
|
|
102
116
|
return false;
|
|
103
117
|
}
|
|
104
118
|
};
|
|
119
|
+
const getEntry = async ({
|
|
120
|
+
contentType,
|
|
121
|
+
documentId,
|
|
122
|
+
locale,
|
|
123
|
+
populate,
|
|
124
|
+
status = "draft"
|
|
125
|
+
}, { strapi: strapi2 }) => {
|
|
126
|
+
if (documentId) {
|
|
127
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
128
|
+
}
|
|
129
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
130
|
+
};
|
|
131
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
132
|
+
if (entry.publishedAt) {
|
|
133
|
+
return "published";
|
|
134
|
+
}
|
|
135
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
136
|
+
documentId: entry.documentId,
|
|
137
|
+
locale: entry.locale,
|
|
138
|
+
status: "published",
|
|
139
|
+
fields: ["updatedAt"]
|
|
140
|
+
});
|
|
141
|
+
if (!publishedEntry) {
|
|
142
|
+
return "draft";
|
|
143
|
+
}
|
|
144
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
145
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
146
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
147
|
+
return "modified";
|
|
148
|
+
}
|
|
149
|
+
return "published";
|
|
150
|
+
};
|
|
105
151
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
106
152
|
oldContentTypes,
|
|
107
153
|
contentTypes: contentTypes2
|
|
@@ -147,20 +193,22 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
147
193
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
148
194
|
for (const action of notValidatedActions) {
|
|
149
195
|
if (action.entry) {
|
|
150
|
-
const
|
|
151
|
-
|
|
196
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
197
|
+
{
|
|
198
|
+
contentType: action.contentType,
|
|
199
|
+
documentId: action.entryDocumentId,
|
|
200
|
+
locale: action.locale
|
|
201
|
+
},
|
|
202
|
+
{ strapi }
|
|
203
|
+
);
|
|
204
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
205
|
+
where: {
|
|
206
|
+
id: action.id
|
|
207
|
+
},
|
|
208
|
+
data: {
|
|
209
|
+
isEntryValid: isEntryValid2
|
|
210
|
+
}
|
|
152
211
|
});
|
|
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
212
|
}
|
|
165
213
|
}
|
|
166
214
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -204,24 +252,24 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
204
252
|
}
|
|
205
253
|
});
|
|
206
254
|
await utils.async.map(actions, async (action) => {
|
|
207
|
-
if (action.entry && action.release) {
|
|
208
|
-
const
|
|
209
|
-
|
|
255
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
256
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
257
|
+
{
|
|
258
|
+
contentType: contentTypeUID,
|
|
259
|
+
documentId: action.entryDocumentId,
|
|
260
|
+
locale: action.locale
|
|
261
|
+
},
|
|
262
|
+
{ strapi }
|
|
263
|
+
);
|
|
264
|
+
releasesAffected.add(action.release.id);
|
|
265
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
266
|
+
where: {
|
|
267
|
+
id: action.id
|
|
268
|
+
},
|
|
269
|
+
data: {
|
|
270
|
+
isEntryValid: isEntryValid2
|
|
271
|
+
}
|
|
210
272
|
});
|
|
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
273
|
}
|
|
226
274
|
});
|
|
227
275
|
}
|
|
@@ -278,9 +326,38 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
278
326
|
}
|
|
279
327
|
}
|
|
280
328
|
}
|
|
329
|
+
const addEntryDocumentToReleaseActions = {
|
|
330
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
331
|
+
async up(trx, db) {
|
|
332
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
333
|
+
if (hasPolymorphicColumn) {
|
|
334
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
335
|
+
"strapi_release_actions",
|
|
336
|
+
"entry_document_id"
|
|
337
|
+
);
|
|
338
|
+
if (!hasEntryDocumentIdColumn) {
|
|
339
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
340
|
+
table.string("entry_document_id");
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
344
|
+
utils.async.map(releaseActions, async (action) => {
|
|
345
|
+
const { target_type, target_id } = action;
|
|
346
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
347
|
+
if (entry) {
|
|
348
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
async down() {
|
|
354
|
+
throw new Error("not implemented");
|
|
355
|
+
}
|
|
356
|
+
};
|
|
281
357
|
const register = async ({ strapi: strapi2 }) => {
|
|
282
358
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
283
359
|
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
360
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
284
361
|
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
285
362
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
286
363
|
}
|
|
@@ -290,6 +367,104 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
290
367
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
291
368
|
}
|
|
292
369
|
};
|
|
370
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
371
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
372
|
+
where: {
|
|
373
|
+
actions: {
|
|
374
|
+
contentType,
|
|
375
|
+
entryDocumentId: entry.documentId,
|
|
376
|
+
locale: entry.locale
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
381
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
382
|
+
where: {
|
|
383
|
+
contentType,
|
|
384
|
+
entryDocumentId: entry.documentId,
|
|
385
|
+
locale: entry.locale
|
|
386
|
+
},
|
|
387
|
+
data: {
|
|
388
|
+
isEntryValid: entryStatus
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
for (const release2 of releases) {
|
|
392
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
396
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
397
|
+
where: {
|
|
398
|
+
actions: params
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
402
|
+
where: params
|
|
403
|
+
});
|
|
404
|
+
for (const release2 of releases) {
|
|
405
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
409
|
+
if (ctx.action !== "delete") {
|
|
410
|
+
return next();
|
|
411
|
+
}
|
|
412
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
413
|
+
return next();
|
|
414
|
+
}
|
|
415
|
+
const contentType = ctx.contentType.uid;
|
|
416
|
+
const { documentId, locale } = ctx.params;
|
|
417
|
+
const result = await next();
|
|
418
|
+
if (!result) {
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
423
|
+
contentType,
|
|
424
|
+
entryDocumentId: documentId,
|
|
425
|
+
...locale !== "*" && { locale }
|
|
426
|
+
});
|
|
427
|
+
} catch (error) {
|
|
428
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
429
|
+
error
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
return result;
|
|
433
|
+
};
|
|
434
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
435
|
+
if (ctx.action !== "update") {
|
|
436
|
+
return next();
|
|
437
|
+
}
|
|
438
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
439
|
+
return next();
|
|
440
|
+
}
|
|
441
|
+
const contentType = ctx.contentType.uid;
|
|
442
|
+
const result = await next();
|
|
443
|
+
if (!result) {
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
450
|
+
error
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
return result;
|
|
454
|
+
};
|
|
455
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
456
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
457
|
+
where: {
|
|
458
|
+
actions: params
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
462
|
+
where: params
|
|
463
|
+
});
|
|
464
|
+
for (const release2 of releases) {
|
|
465
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
293
468
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
294
469
|
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
295
470
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
@@ -297,115 +472,29 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
297
472
|
);
|
|
298
473
|
strapi2.db.lifecycles.subscribe({
|
|
299
474
|
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
475
|
/**
|
|
328
|
-
* deleteMany
|
|
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
|
-
/**
|
|
340
|
-
* We delete the release actions related to deleted entries
|
|
341
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
476
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
342
477
|
*/
|
|
343
478
|
async afterDeleteMany(event) {
|
|
344
479
|
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
|
-
}
|
|
480
|
+
const model = strapi2.getModel(event.model.uid);
|
|
481
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
482
|
+
const { where } = event.params;
|
|
483
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
484
|
+
contentType: model.uid,
|
|
485
|
+
locale: where.locale ?? null,
|
|
486
|
+
...where.documentId && { entryDocumentId: where.documentId }
|
|
365
487
|
});
|
|
366
|
-
for (const release2 of releases) {
|
|
367
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
368
|
-
}
|
|
369
488
|
}
|
|
370
489
|
} catch (error) {
|
|
371
490
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
372
491
|
error
|
|
373
492
|
});
|
|
374
493
|
}
|
|
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
494
|
}
|
|
408
495
|
});
|
|
496
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
497
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
409
498
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
410
499
|
strapi2.log.error(
|
|
411
500
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -497,15 +586,13 @@ const schema = {
|
|
|
497
586
|
enum: ["publish", "unpublish"],
|
|
498
587
|
required: true
|
|
499
588
|
},
|
|
500
|
-
entry: {
|
|
501
|
-
type: "relation",
|
|
502
|
-
relation: "morphToOne",
|
|
503
|
-
configurable: false
|
|
504
|
-
},
|
|
505
589
|
contentType: {
|
|
506
590
|
type: "string",
|
|
507
591
|
required: true
|
|
508
592
|
},
|
|
593
|
+
entryDocumentId: {
|
|
594
|
+
type: "string"
|
|
595
|
+
},
|
|
509
596
|
locale: {
|
|
510
597
|
type: "string"
|
|
511
598
|
},
|
|
@@ -527,18 +614,6 @@ const contentTypes = {
|
|
|
527
614
|
release: release$1,
|
|
528
615
|
"release-action": releaseAction$1
|
|
529
616
|
};
|
|
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
617
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
543
618
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
544
619
|
strapi2.eventHub.emit(event, {
|
|
@@ -547,93 +622,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
547
622
|
release: release2
|
|
548
623
|
});
|
|
549
624
|
};
|
|
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
625
|
const getFormattedActions = async (releaseId) => {
|
|
597
626
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
598
627
|
where: {
|
|
599
628
|
release: {
|
|
600
629
|
id: releaseId
|
|
601
630
|
}
|
|
602
|
-
},
|
|
603
|
-
populate: {
|
|
604
|
-
entry: {
|
|
605
|
-
fields: ["id"]
|
|
606
|
-
}
|
|
607
631
|
}
|
|
608
632
|
});
|
|
609
633
|
if (actions.length === 0) {
|
|
610
634
|
throw new utils.errors.ValidationError("No entries to publish");
|
|
611
635
|
}
|
|
612
|
-
const
|
|
613
|
-
const singleTypeActions = [];
|
|
636
|
+
const formattedActions = {};
|
|
614
637
|
for (const action of actions) {
|
|
615
638
|
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
|
-
});
|
|
639
|
+
if (!formattedActions[contentTypeUid]) {
|
|
640
|
+
formattedActions[contentTypeUid] = {
|
|
641
|
+
publish: [],
|
|
642
|
+
unpublish: []
|
|
643
|
+
};
|
|
634
644
|
}
|
|
645
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
646
|
+
documentId: action.entryDocumentId,
|
|
647
|
+
locale: action.locale
|
|
648
|
+
});
|
|
635
649
|
}
|
|
636
|
-
return
|
|
650
|
+
return formattedActions;
|
|
637
651
|
};
|
|
638
652
|
return {
|
|
639
653
|
async create(releaseData, { user }) {
|
|
@@ -680,91 +694,10 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
680
694
|
}
|
|
681
695
|
});
|
|
682
696
|
},
|
|
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;
|
|
697
|
+
findMany(query) {
|
|
698
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
699
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
700
|
+
...dbQuery
|
|
768
701
|
});
|
|
769
702
|
},
|
|
770
703
|
async update(id, releaseData, { user }) {
|
|
@@ -800,12 +733,208 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
800
733
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
801
734
|
return updatedRelease;
|
|
802
735
|
},
|
|
803
|
-
async
|
|
804
|
-
const
|
|
736
|
+
async getAllComponents() {
|
|
737
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
738
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
739
|
+
const componentsMap = components.reduce(
|
|
740
|
+
(acc, component) => {
|
|
741
|
+
acc[component.uid] = component;
|
|
742
|
+
return acc;
|
|
743
|
+
},
|
|
744
|
+
{}
|
|
745
|
+
);
|
|
746
|
+
return componentsMap;
|
|
747
|
+
},
|
|
748
|
+
async delete(releaseId) {
|
|
749
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
750
|
+
where: { id: releaseId },
|
|
751
|
+
populate: {
|
|
752
|
+
actions: {
|
|
753
|
+
select: ["id"]
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
if (!release2) {
|
|
758
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
759
|
+
}
|
|
760
|
+
if (release2.releasedAt) {
|
|
761
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
762
|
+
}
|
|
763
|
+
await strapi2.db.transaction(async () => {
|
|
764
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
765
|
+
where: {
|
|
766
|
+
id: {
|
|
767
|
+
$in: release2.actions.map((action) => action.id)
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
772
|
+
where: {
|
|
773
|
+
id: releaseId
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
if (release2.scheduledAt) {
|
|
778
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
779
|
+
await schedulingService.cancel(release2.id);
|
|
780
|
+
}
|
|
781
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
782
|
+
return release2;
|
|
783
|
+
},
|
|
784
|
+
async publish(releaseId) {
|
|
785
|
+
const {
|
|
786
|
+
release: release2,
|
|
787
|
+
error
|
|
788
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
789
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
790
|
+
if (!lockedRelease) {
|
|
791
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
792
|
+
}
|
|
793
|
+
if (lockedRelease.releasedAt) {
|
|
794
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
795
|
+
}
|
|
796
|
+
if (lockedRelease.status === "failed") {
|
|
797
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
798
|
+
}
|
|
799
|
+
try {
|
|
800
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
801
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
802
|
+
await strapi2.db.transaction(
|
|
803
|
+
async () => Promise.all(
|
|
804
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
805
|
+
const contentType = contentTypeUid;
|
|
806
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
807
|
+
return Promise.all([
|
|
808
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
809
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
810
|
+
]);
|
|
811
|
+
})
|
|
812
|
+
)
|
|
813
|
+
);
|
|
814
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
815
|
+
where: {
|
|
816
|
+
id: releaseId
|
|
817
|
+
},
|
|
818
|
+
data: {
|
|
819
|
+
status: "done",
|
|
820
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
824
|
+
isPublished: true,
|
|
825
|
+
release: release22
|
|
826
|
+
});
|
|
827
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
828
|
+
return { release: release22, error: null };
|
|
829
|
+
} catch (error2) {
|
|
830
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
831
|
+
isPublished: false,
|
|
832
|
+
error: error2
|
|
833
|
+
});
|
|
834
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
835
|
+
status: "failed"
|
|
836
|
+
}).transacting(trx).execute();
|
|
837
|
+
return {
|
|
838
|
+
release: null,
|
|
839
|
+
error: error2
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
if (error instanceof Error) {
|
|
844
|
+
throw error;
|
|
845
|
+
}
|
|
846
|
+
return release2;
|
|
847
|
+
},
|
|
848
|
+
async updateReleaseStatus(releaseId) {
|
|
849
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
850
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
851
|
+
releaseActionService.countActions({
|
|
852
|
+
filters: {
|
|
853
|
+
release: releaseId
|
|
854
|
+
}
|
|
855
|
+
}),
|
|
856
|
+
releaseActionService.countActions({
|
|
857
|
+
filters: {
|
|
858
|
+
release: releaseId,
|
|
859
|
+
isEntryValid: false
|
|
860
|
+
}
|
|
861
|
+
})
|
|
862
|
+
]);
|
|
863
|
+
if (totalActions > 0) {
|
|
864
|
+
if (invalidActions > 0) {
|
|
865
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
866
|
+
where: {
|
|
867
|
+
id: releaseId
|
|
868
|
+
},
|
|
869
|
+
data: {
|
|
870
|
+
status: "blocked"
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
875
|
+
where: {
|
|
876
|
+
id: releaseId
|
|
877
|
+
},
|
|
878
|
+
data: {
|
|
879
|
+
status: "ready"
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
884
|
+
where: {
|
|
885
|
+
id: releaseId
|
|
886
|
+
},
|
|
887
|
+
data: {
|
|
888
|
+
status: "empty"
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
};
|
|
894
|
+
const getGroupName = (queryValue) => {
|
|
895
|
+
switch (queryValue) {
|
|
896
|
+
case "contentType":
|
|
897
|
+
return "contentType.displayName";
|
|
898
|
+
case "type":
|
|
899
|
+
return "type";
|
|
900
|
+
case "locale":
|
|
901
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
902
|
+
default:
|
|
903
|
+
return "contentType.displayName";
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
907
|
+
const getLocalesDataForActions = async () => {
|
|
908
|
+
if (!strapi2.plugin("i18n")) {
|
|
909
|
+
return {};
|
|
910
|
+
}
|
|
911
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
912
|
+
return allLocales.reduce((acc, locale) => {
|
|
913
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
914
|
+
return acc;
|
|
915
|
+
}, {});
|
|
916
|
+
};
|
|
917
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
918
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
919
|
+
const contentTypesData = {};
|
|
920
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
921
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
922
|
+
uid: contentTypeUid
|
|
923
|
+
});
|
|
924
|
+
contentTypesData[contentTypeUid] = {
|
|
925
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
926
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
return contentTypesData;
|
|
930
|
+
};
|
|
931
|
+
return {
|
|
932
|
+
async create(releaseId, action) {
|
|
933
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
805
934
|
strapi: strapi2
|
|
806
935
|
});
|
|
807
936
|
await Promise.all([
|
|
808
|
-
|
|
937
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
809
938
|
validateUniqueEntry(releaseId, action)
|
|
810
939
|
]);
|
|
811
940
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
@@ -815,28 +944,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
815
944
|
if (release2.releasedAt) {
|
|
816
945
|
throw new utils.errors.ValidationError("Release already published");
|
|
817
946
|
}
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
947
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
948
|
+
{
|
|
949
|
+
contentType: action.contentType,
|
|
950
|
+
documentId: action.entryDocumentId,
|
|
951
|
+
locale: action.locale
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
strapi: strapi2
|
|
955
|
+
}
|
|
956
|
+
) : true;
|
|
821
957
|
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
822
958
|
data: {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
isEntryValid,
|
|
827
|
-
entry: {
|
|
828
|
-
id: entry.id,
|
|
829
|
-
__type: entry.contentType,
|
|
830
|
-
__pivot: { field: "entry" }
|
|
831
|
-
},
|
|
832
|
-
release: releaseId
|
|
959
|
+
...action,
|
|
960
|
+
release: release2.id,
|
|
961
|
+
isEntryValid: actionStatus
|
|
833
962
|
},
|
|
834
|
-
populate: { release: { select: ["id"] }
|
|
963
|
+
populate: { release: { select: ["id"] } }
|
|
835
964
|
});
|
|
836
|
-
|
|
965
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
837
966
|
return releaseAction2;
|
|
838
967
|
},
|
|
839
|
-
async
|
|
968
|
+
async findPage(releaseId, query) {
|
|
840
969
|
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
841
970
|
where: { id: releaseId },
|
|
842
971
|
select: ["id"]
|
|
@@ -845,21 +974,35 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
845
974
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
846
975
|
}
|
|
847
976
|
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
848
|
-
|
|
977
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
849
978
|
...dbQuery,
|
|
850
|
-
populate: {
|
|
851
|
-
entry: {
|
|
852
|
-
populate: "*"
|
|
853
|
-
}
|
|
854
|
-
},
|
|
855
979
|
where: {
|
|
856
980
|
release: releaseId
|
|
857
981
|
}
|
|
858
982
|
});
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
983
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
984
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
985
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
986
|
+
const entry = await getEntry(
|
|
987
|
+
{
|
|
988
|
+
contentType: action.contentType,
|
|
989
|
+
documentId: action.entryDocumentId,
|
|
990
|
+
locale: action.locale,
|
|
991
|
+
populate,
|
|
992
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
993
|
+
},
|
|
994
|
+
{ strapi: strapi2 }
|
|
995
|
+
);
|
|
996
|
+
return {
|
|
997
|
+
...action,
|
|
998
|
+
entry,
|
|
999
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1000
|
+
};
|
|
1001
|
+
});
|
|
1002
|
+
return {
|
|
1003
|
+
results: actionsWithEntry,
|
|
1004
|
+
pagination
|
|
1005
|
+
};
|
|
863
1006
|
},
|
|
864
1007
|
async groupActions(actions, groupBy) {
|
|
865
1008
|
const contentTypeUids = actions.reduce((acc, action) => {
|
|
@@ -868,8 +1011,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
868
1011
|
}
|
|
869
1012
|
return acc;
|
|
870
1013
|
}, []);
|
|
871
|
-
const allReleaseContentTypesDictionary = await
|
|
872
|
-
const allLocalesDictionary = await
|
|
1014
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1015
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
873
1016
|
const formattedData = actions.map((action) => {
|
|
874
1017
|
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
875
1018
|
return {
|
|
@@ -880,165 +1023,58 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
880
1023
|
mainFieldValue: action.entry[mainField],
|
|
881
1024
|
uid: action.contentType
|
|
882
1025
|
}
|
|
883
|
-
};
|
|
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
|
-
});
|
|
1026
|
+
};
|
|
968
1027
|
});
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
await schedulingService.cancel(release2.id);
|
|
972
|
-
}
|
|
973
|
-
strapi2.telemetry.send("didDeleteContentRelease");
|
|
974
|
-
return release2;
|
|
1028
|
+
const groupName = getGroupName(groupBy);
|
|
1029
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
975
1030
|
},
|
|
976
|
-
|
|
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");
|
|
1031
|
+
getContentTypeModelsFromActions(actions) {
|
|
1032
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1033
|
+
if (!acc.includes(action.contentType)) {
|
|
1034
|
+
acc.push(action.contentType);
|
|
990
1035
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1036
|
+
return acc;
|
|
1037
|
+
}, []);
|
|
1038
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1039
|
+
(acc, contentTypeUid) => {
|
|
1040
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1041
|
+
return acc;
|
|
1042
|
+
},
|
|
1043
|
+
{}
|
|
1044
|
+
);
|
|
1045
|
+
return contentTypeModelsMap;
|
|
1046
|
+
},
|
|
1047
|
+
async countActions(query) {
|
|
1048
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1049
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1050
|
+
},
|
|
1051
|
+
async update(actionId, releaseId, update) {
|
|
1052
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1053
|
+
where: {
|
|
1054
|
+
id: actionId,
|
|
1055
|
+
release: {
|
|
1056
|
+
id: releaseId,
|
|
1057
|
+
releasedAt: {
|
|
1058
|
+
$null: true
|
|
1014
1059
|
}
|
|
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
|
|
1026
|
-
});
|
|
1027
|
-
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
1028
|
-
status: "failed"
|
|
1029
|
-
}).transacting(trx).execute();
|
|
1030
|
-
return {
|
|
1031
|
-
release: null,
|
|
1032
|
-
error: error2
|
|
1033
|
-
};
|
|
1060
|
+
}
|
|
1034
1061
|
}
|
|
1035
1062
|
});
|
|
1036
|
-
if (
|
|
1037
|
-
throw
|
|
1063
|
+
if (!action) {
|
|
1064
|
+
throw new utils.errors.NotFoundError(
|
|
1065
|
+
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1066
|
+
);
|
|
1038
1067
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1068
|
+
const actionStatus = update.type === "publish" ? getDraftEntryValidStatus(
|
|
1069
|
+
{
|
|
1070
|
+
contentType: action.contentType,
|
|
1071
|
+
documentId: action.entryDocumentId,
|
|
1072
|
+
locale: action.locale
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
strapi: strapi2
|
|
1076
|
+
}
|
|
1077
|
+
) : true;
|
|
1042
1078
|
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1043
1079
|
where: {
|
|
1044
1080
|
id: actionId,
|
|
@@ -1049,16 +1085,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1049
1085
|
}
|
|
1050
1086
|
}
|
|
1051
1087
|
},
|
|
1052
|
-
data:
|
|
1088
|
+
data: {
|
|
1089
|
+
...update,
|
|
1090
|
+
isEntryValid: actionStatus
|
|
1091
|
+
}
|
|
1053
1092
|
});
|
|
1054
|
-
|
|
1055
|
-
throw new utils.errors.NotFoundError(
|
|
1056
|
-
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1057
|
-
);
|
|
1058
|
-
}
|
|
1093
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1059
1094
|
return updatedAction;
|
|
1060
1095
|
},
|
|
1061
|
-
async
|
|
1096
|
+
async delete(actionId, releaseId) {
|
|
1062
1097
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1063
1098
|
where: {
|
|
1064
1099
|
id: actionId,
|
|
@@ -1075,51 +1110,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1075
1110
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1076
1111
|
);
|
|
1077
1112
|
}
|
|
1078
|
-
|
|
1113
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1079
1114
|
return deletedAction;
|
|
1080
|
-
},
|
|
1081
|
-
async updateReleaseStatus(releaseId) {
|
|
1082
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
1083
|
-
this.countActions({
|
|
1084
|
-
filters: {
|
|
1085
|
-
release: releaseId
|
|
1086
|
-
}
|
|
1087
|
-
}),
|
|
1088
|
-
this.countActions({
|
|
1089
|
-
filters: {
|
|
1090
|
-
release: releaseId,
|
|
1091
|
-
isEntryValid: false
|
|
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"
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
}
|
|
1106
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1107
|
-
where: {
|
|
1108
|
-
id: releaseId
|
|
1109
|
-
},
|
|
1110
|
-
data: {
|
|
1111
|
-
status: "ready"
|
|
1112
|
-
}
|
|
1113
|
-
});
|
|
1114
|
-
}
|
|
1115
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1116
|
-
where: {
|
|
1117
|
-
id: releaseId
|
|
1118
|
-
},
|
|
1119
|
-
data: {
|
|
1120
|
-
status: "empty"
|
|
1121
|
-
}
|
|
1122
|
-
});
|
|
1123
1115
|
}
|
|
1124
1116
|
};
|
|
1125
1117
|
};
|
|
@@ -1135,30 +1127,35 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1135
1127
|
where: {
|
|
1136
1128
|
id: releaseId
|
|
1137
1129
|
},
|
|
1138
|
-
populate: {
|
|
1130
|
+
populate: {
|
|
1131
|
+
actions: true
|
|
1132
|
+
}
|
|
1139
1133
|
});
|
|
1140
1134
|
if (!release2) {
|
|
1141
1135
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1142
1136
|
}
|
|
1143
1137
|
const isEntryInRelease = release2.actions.some(
|
|
1144
|
-
(action) =>
|
|
1138
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1145
1139
|
);
|
|
1146
1140
|
if (isEntryInRelease) {
|
|
1147
1141
|
throw new AlreadyOnReleaseError(
|
|
1148
|
-
`Entry with
|
|
1142
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1149
1143
|
);
|
|
1150
1144
|
}
|
|
1151
1145
|
},
|
|
1152
|
-
|
|
1146
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1153
1147
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1154
1148
|
if (!contentType) {
|
|
1155
1149
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1156
1150
|
}
|
|
1157
|
-
if (!contentType
|
|
1151
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1158
1152
|
throw new utils.errors.ValidationError(
|
|
1159
1153
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1160
1154
|
);
|
|
1161
1155
|
}
|
|
1156
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1157
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1158
|
+
}
|
|
1162
1159
|
},
|
|
1163
1160
|
async validatePendingReleasesLimit() {
|
|
1164
1161
|
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
@@ -1247,78 +1244,152 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1247
1244
|
}
|
|
1248
1245
|
};
|
|
1249
1246
|
};
|
|
1247
|
+
const DEFAULT_SETTINGS = {
|
|
1248
|
+
defaultTimezone: null
|
|
1249
|
+
};
|
|
1250
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1251
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1252
|
+
return {
|
|
1253
|
+
async update({ settings: settings2 }) {
|
|
1254
|
+
const store = await getStore();
|
|
1255
|
+
store.set({ key: "settings", value: settings2 });
|
|
1256
|
+
return settings2;
|
|
1257
|
+
},
|
|
1258
|
+
async find() {
|
|
1259
|
+
const store = await getStore();
|
|
1260
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1261
|
+
return {
|
|
1262
|
+
...DEFAULT_SETTINGS,
|
|
1263
|
+
...settings2 || {}
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
};
|
|
1250
1268
|
const services = {
|
|
1251
1269
|
release: createReleaseService,
|
|
1270
|
+
"release-action": createReleaseActionService,
|
|
1252
1271
|
"release-validation": createReleaseValidationService,
|
|
1253
|
-
scheduling: createSchedulingService
|
|
1272
|
+
scheduling: createSchedulingService,
|
|
1273
|
+
settings: createSettingsService
|
|
1254
1274
|
};
|
|
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()
|
|
1275
|
+
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1276
|
+
name: utils.yup.string().trim().required(),
|
|
1277
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1278
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1279
|
+
is: (value) => value !== null && value !== void 0,
|
|
1280
|
+
then: utils.yup.string().required(),
|
|
1281
|
+
otherwise: utils.yup.string().nullable()
|
|
1273
1282
|
})
|
|
1274
1283
|
}).required().noUnknown();
|
|
1284
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1285
|
+
contentType: utils.yup.string().required(),
|
|
1286
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1287
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1288
|
+
locale: utils.yup.string().nullable()
|
|
1289
|
+
}).required().noUnknown();
|
|
1275
1290
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1291
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1292
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1293
|
+
);
|
|
1276
1294
|
const releaseController = {
|
|
1277
|
-
|
|
1295
|
+
/**
|
|
1296
|
+
* Find releases based on documents attached or not to the release.
|
|
1297
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1298
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1299
|
+
*/
|
|
1300
|
+
async findByDocumentAttached(ctx) {
|
|
1278
1301
|
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1279
1302
|
ability: ctx.state.userAbility,
|
|
1280
1303
|
model: RELEASE_MODEL_UID
|
|
1281
1304
|
});
|
|
1282
1305
|
await permissionsManager.validateQuery(ctx.query);
|
|
1283
1306
|
const releaseService = getService("release", { strapi });
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1291
|
-
|
|
1307
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1308
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1309
|
+
const { contentType, entryDocumentId, hasEntryAttached, locale } = query;
|
|
1310
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1311
|
+
if (isEntryAttached) {
|
|
1312
|
+
const releases = await releaseService.findMany({
|
|
1313
|
+
where: {
|
|
1314
|
+
releasedAt: null,
|
|
1315
|
+
actions: {
|
|
1316
|
+
contentType,
|
|
1317
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1318
|
+
locale: locale ?? null
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
1321
|
+
populate: {
|
|
1322
|
+
actions: {
|
|
1323
|
+
fields: ["type"]
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
});
|
|
1327
|
+
ctx.body = { data: releases };
|
|
1292
1328
|
} else {
|
|
1293
|
-
const
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
const { actions, ...releaseData } = release2;
|
|
1297
|
-
return {
|
|
1298
|
-
...releaseData,
|
|
1329
|
+
const relatedReleases = await releaseService.findMany({
|
|
1330
|
+
where: {
|
|
1331
|
+
releasedAt: null,
|
|
1299
1332
|
actions: {
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1333
|
+
contentType,
|
|
1334
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1335
|
+
locale: locale ?? null
|
|
1303
1336
|
}
|
|
1304
|
-
}
|
|
1337
|
+
}
|
|
1305
1338
|
});
|
|
1306
|
-
const
|
|
1339
|
+
const releases = await releaseService.findMany({
|
|
1307
1340
|
where: {
|
|
1341
|
+
$or: [
|
|
1342
|
+
{
|
|
1343
|
+
id: {
|
|
1344
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
actions: null
|
|
1349
|
+
}
|
|
1350
|
+
],
|
|
1308
1351
|
releasedAt: null
|
|
1309
1352
|
}
|
|
1310
1353
|
});
|
|
1311
|
-
ctx.body = { data
|
|
1354
|
+
ctx.body = { data: releases };
|
|
1312
1355
|
}
|
|
1313
1356
|
},
|
|
1357
|
+
async findPage(ctx) {
|
|
1358
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1359
|
+
ability: ctx.state.userAbility,
|
|
1360
|
+
model: RELEASE_MODEL_UID
|
|
1361
|
+
});
|
|
1362
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1363
|
+
const releaseService = getService("release", { strapi });
|
|
1364
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1365
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1366
|
+
const data = results.map((release2) => {
|
|
1367
|
+
const { actions, ...releaseData } = release2;
|
|
1368
|
+
return {
|
|
1369
|
+
...releaseData,
|
|
1370
|
+
actions: {
|
|
1371
|
+
meta: {
|
|
1372
|
+
count: actions.count
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
});
|
|
1377
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1378
|
+
where: {
|
|
1379
|
+
releasedAt: null
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1383
|
+
},
|
|
1314
1384
|
async findOne(ctx) {
|
|
1315
1385
|
const id = ctx.params.id;
|
|
1316
1386
|
const releaseService = getService("release", { strapi });
|
|
1387
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1317
1388
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1318
1389
|
if (!release2) {
|
|
1319
1390
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1320
1391
|
}
|
|
1321
|
-
const count = await
|
|
1392
|
+
const count = await releaseActionService.countActions({
|
|
1322
1393
|
filters: {
|
|
1323
1394
|
release: id
|
|
1324
1395
|
}
|
|
@@ -1338,28 +1409,43 @@ const releaseController = {
|
|
|
1338
1409
|
ctx.body = { data };
|
|
1339
1410
|
},
|
|
1340
1411
|
async mapEntriesToReleases(ctx) {
|
|
1341
|
-
const { contentTypeUid,
|
|
1342
|
-
if (!contentTypeUid || !
|
|
1412
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1413
|
+
if (!contentTypeUid || !documentIds) {
|
|
1343
1414
|
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1344
1415
|
}
|
|
1345
1416
|
const releaseService = getService("release", { strapi });
|
|
1346
|
-
const releasesWithActions = await releaseService.
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1417
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1418
|
+
where: {
|
|
1419
|
+
releasedAt: null,
|
|
1420
|
+
actions: {
|
|
1421
|
+
contentType: contentTypeUid,
|
|
1422
|
+
entryDocumentId: {
|
|
1423
|
+
$in: documentIds
|
|
1424
|
+
},
|
|
1425
|
+
locale
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1428
|
+
populate: {
|
|
1429
|
+
actions: true
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1350
1432
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1351
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1352
1433
|
(acc, release2) => {
|
|
1353
1434
|
release2.actions.forEach((action) => {
|
|
1354
|
-
if (
|
|
1355
|
-
|
|
1435
|
+
if (action.contentType !== contentTypeUid) {
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
if (locale && action.locale !== locale) {
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
if (!acc[action.entryDocumentId]) {
|
|
1442
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1356
1443
|
} else {
|
|
1357
|
-
acc[action.
|
|
1444
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1358
1445
|
}
|
|
1359
1446
|
});
|
|
1360
1447
|
return acc;
|
|
1361
1448
|
},
|
|
1362
|
-
// TODO: Fix for v5 removed mappedEntriedToRelease
|
|
1363
1449
|
{}
|
|
1364
1450
|
);
|
|
1365
1451
|
ctx.body = {
|
|
@@ -1404,18 +1490,18 @@ const releaseController = {
|
|
|
1404
1490
|
};
|
|
1405
1491
|
},
|
|
1406
1492
|
async publish(ctx) {
|
|
1407
|
-
const user = ctx.state.user;
|
|
1408
1493
|
const id = ctx.params.id;
|
|
1409
1494
|
const releaseService = getService("release", { strapi });
|
|
1410
|
-
const
|
|
1495
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1496
|
+
const release2 = await releaseService.publish(id);
|
|
1411
1497
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1412
|
-
|
|
1498
|
+
releaseActionService.countActions({
|
|
1413
1499
|
filters: {
|
|
1414
1500
|
release: id,
|
|
1415
1501
|
type: "publish"
|
|
1416
1502
|
}
|
|
1417
1503
|
}),
|
|
1418
|
-
|
|
1504
|
+
releaseActionService.countActions({
|
|
1419
1505
|
filters: {
|
|
1420
1506
|
release: id,
|
|
1421
1507
|
type: "unpublish"
|
|
@@ -1433,24 +1519,27 @@ const releaseController = {
|
|
|
1433
1519
|
}
|
|
1434
1520
|
};
|
|
1435
1521
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
}).required(),
|
|
1522
|
+
contentType: utils.yup.string().required(),
|
|
1523
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1524
|
+
locale: utils.yup.string(),
|
|
1440
1525
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1441
1526
|
});
|
|
1442
1527
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1443
1528
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1444
1529
|
});
|
|
1530
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1531
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1532
|
+
});
|
|
1445
1533
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1446
1534
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1535
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1447
1536
|
const releaseActionController = {
|
|
1448
1537
|
async create(ctx) {
|
|
1449
1538
|
const releaseId = ctx.params.releaseId;
|
|
1450
1539
|
const releaseActionArgs = ctx.request.body;
|
|
1451
1540
|
await validateReleaseAction(releaseActionArgs);
|
|
1452
|
-
const
|
|
1453
|
-
const releaseAction2 = await
|
|
1541
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1542
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1454
1543
|
ctx.created({
|
|
1455
1544
|
data: releaseAction2
|
|
1456
1545
|
});
|
|
@@ -1461,12 +1550,12 @@ const releaseActionController = {
|
|
|
1461
1550
|
await Promise.all(
|
|
1462
1551
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1463
1552
|
);
|
|
1464
|
-
const
|
|
1553
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1465
1554
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1466
1555
|
const releaseActions2 = await Promise.all(
|
|
1467
1556
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1468
1557
|
try {
|
|
1469
|
-
const action = await
|
|
1558
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1470
1559
|
return action;
|
|
1471
1560
|
} catch (error) {
|
|
1472
1561
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1493,10 +1582,17 @@ const releaseActionController = {
|
|
|
1493
1582
|
ability: ctx.state.userAbility,
|
|
1494
1583
|
model: RELEASE_ACTION_MODEL_UID
|
|
1495
1584
|
});
|
|
1585
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1586
|
+
if (ctx.query.groupBy) {
|
|
1587
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1588
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1592
|
+
delete ctx.query.groupBy;
|
|
1496
1593
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1497
|
-
const
|
|
1498
|
-
const { results, pagination } = await
|
|
1499
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1594
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1595
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1500
1596
|
...query
|
|
1501
1597
|
});
|
|
1502
1598
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
@@ -1512,10 +1608,11 @@ const releaseActionController = {
|
|
|
1512
1608
|
}, {});
|
|
1513
1609
|
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1514
1610
|
...action,
|
|
1515
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1611
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1516
1612
|
}));
|
|
1517
|
-
const groupedData = await
|
|
1518
|
-
const contentTypes2 =
|
|
1613
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1614
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1615
|
+
const releaseService = getService("release", { strapi });
|
|
1519
1616
|
const components = await releaseService.getAllComponents();
|
|
1520
1617
|
ctx.body = {
|
|
1521
1618
|
data: groupedData,
|
|
@@ -1531,8 +1628,8 @@ const releaseActionController = {
|
|
|
1531
1628
|
const releaseId = ctx.params.releaseId;
|
|
1532
1629
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1533
1630
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1534
|
-
const
|
|
1535
|
-
const updatedAction = await
|
|
1631
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1632
|
+
const updatedAction = await releaseActionService.update(
|
|
1536
1633
|
actionId,
|
|
1537
1634
|
releaseId,
|
|
1538
1635
|
releaseActionUpdateArgs
|
|
@@ -1544,14 +1641,36 @@ const releaseActionController = {
|
|
|
1544
1641
|
async delete(ctx) {
|
|
1545
1642
|
const actionId = ctx.params.actionId;
|
|
1546
1643
|
const releaseId = ctx.params.releaseId;
|
|
1547
|
-
const
|
|
1548
|
-
const deletedReleaseAction = await
|
|
1644
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1645
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1549
1646
|
ctx.body = {
|
|
1550
1647
|
data: deletedReleaseAction
|
|
1551
1648
|
};
|
|
1552
1649
|
}
|
|
1553
1650
|
};
|
|
1554
|
-
const
|
|
1651
|
+
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1652
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1653
|
+
}).required().noUnknown();
|
|
1654
|
+
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1655
|
+
const settingsController = {
|
|
1656
|
+
async find(ctx) {
|
|
1657
|
+
const settingsService = getService("settings", { strapi });
|
|
1658
|
+
const settings2 = await settingsService.find();
|
|
1659
|
+
ctx.body = { data: settings2 };
|
|
1660
|
+
},
|
|
1661
|
+
async update(ctx) {
|
|
1662
|
+
const settingsBody = ctx.request.body;
|
|
1663
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1664
|
+
const settingsService = getService("settings", { strapi });
|
|
1665
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1666
|
+
ctx.body = { data: updatedSettings };
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
const controllers = {
|
|
1670
|
+
release: releaseController,
|
|
1671
|
+
"release-action": releaseActionController,
|
|
1672
|
+
settings: settingsController
|
|
1673
|
+
};
|
|
1555
1674
|
const release = {
|
|
1556
1675
|
type: "admin",
|
|
1557
1676
|
routes: [
|
|
@@ -1571,6 +1690,22 @@ const release = {
|
|
|
1571
1690
|
]
|
|
1572
1691
|
}
|
|
1573
1692
|
},
|
|
1693
|
+
{
|
|
1694
|
+
method: "GET",
|
|
1695
|
+
path: "/getByDocumentAttached",
|
|
1696
|
+
handler: "release.findByDocumentAttached",
|
|
1697
|
+
config: {
|
|
1698
|
+
policies: [
|
|
1699
|
+
"admin::isAuthenticatedAdmin",
|
|
1700
|
+
{
|
|
1701
|
+
name: "admin::hasPermissions",
|
|
1702
|
+
config: {
|
|
1703
|
+
actions: ["plugin::content-releases.read"]
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
]
|
|
1707
|
+
}
|
|
1708
|
+
},
|
|
1574
1709
|
{
|
|
1575
1710
|
method: "POST",
|
|
1576
1711
|
path: "/",
|
|
@@ -1590,7 +1725,7 @@ const release = {
|
|
|
1590
1725
|
{
|
|
1591
1726
|
method: "GET",
|
|
1592
1727
|
path: "/",
|
|
1593
|
-
handler: "release.
|
|
1728
|
+
handler: "release.findPage",
|
|
1594
1729
|
config: {
|
|
1595
1730
|
policies: [
|
|
1596
1731
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1754,7 +1889,45 @@ const releaseAction = {
|
|
|
1754
1889
|
}
|
|
1755
1890
|
]
|
|
1756
1891
|
};
|
|
1892
|
+
const settings = {
|
|
1893
|
+
type: "admin",
|
|
1894
|
+
routes: [
|
|
1895
|
+
{
|
|
1896
|
+
method: "GET",
|
|
1897
|
+
path: "/settings",
|
|
1898
|
+
handler: "settings.find",
|
|
1899
|
+
config: {
|
|
1900
|
+
policies: [
|
|
1901
|
+
"admin::isAuthenticatedAdmin",
|
|
1902
|
+
{
|
|
1903
|
+
name: "admin::hasPermissions",
|
|
1904
|
+
config: {
|
|
1905
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
]
|
|
1909
|
+
}
|
|
1910
|
+
},
|
|
1911
|
+
{
|
|
1912
|
+
method: "PUT",
|
|
1913
|
+
path: "/settings",
|
|
1914
|
+
handler: "settings.update",
|
|
1915
|
+
config: {
|
|
1916
|
+
policies: [
|
|
1917
|
+
"admin::isAuthenticatedAdmin",
|
|
1918
|
+
{
|
|
1919
|
+
name: "admin::hasPermissions",
|
|
1920
|
+
config: {
|
|
1921
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
]
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
]
|
|
1928
|
+
};
|
|
1757
1929
|
const routes = {
|
|
1930
|
+
settings,
|
|
1758
1931
|
release,
|
|
1759
1932
|
"release-action": releaseAction
|
|
1760
1933
|
};
|