@strapi/content-releases 0.0.0-next.f4ff842a3cb7b83db540bee67554b704e042b042 → 0.0.0-next.f6dca5adf05ef6bed9605a1535999ab0bbbf063e
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-BKB1esYS.js +1395 -0
- package/dist/_chunks/App-BKB1esYS.js.map +1 -0
- package/dist/_chunks/{App-jrh58sXY.mjs → App-Cne--1Z8.mjs} +602 -558
- package/dist/_chunks/App-Cne--1Z8.mjs.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-bpIYXOfu.js → PurchaseContentReleases-Be3acS2L.js} +7 -6
- package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +1 -0
- package/dist/_chunks/{PurchaseContentReleases-3tRbmbY3.mjs → PurchaseContentReleases-_MxP6-Dt.mjs} +8 -7
- package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-C1WwGWIH.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-kuXIwpWp.js.map +1 -0
- package/dist/_chunks/{en-HrREghh3.js → en-CmYoEnA7.js} +9 -2
- package/dist/_chunks/en-CmYoEnA7.js.map +1 -0
- package/dist/_chunks/{en-ltT1TlKQ.mjs → en-D0yVZFqf.mjs} +9 -2
- package/dist/_chunks/en-D0yVZFqf.mjs.map +1 -0
- package/dist/_chunks/index-5Odi61vw.js +1381 -0
- package/dist/_chunks/index-5Odi61vw.js.map +1 -0
- package/dist/_chunks/index-Cy7qwpaU.mjs +1362 -0
- package/dist/_chunks/index-Cy7qwpaU.mjs.map +1 -0
- package/dist/_chunks/schemas-BE1LxE9J.js +62 -0
- package/dist/_chunks/schemas-BE1LxE9J.js.map +1 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
- package/dist/admin/index.js +1 -15
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +2 -16
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/RelativeTime.d.ts +28 -0
- package/dist/admin/src/components/ReleaseAction.d.ts +3 -0
- package/dist/admin/src/components/ReleaseActionMenu.d.ts +26 -0
- package/dist/admin/src/components/ReleaseActionModal.d.ts +24 -0
- package/dist/admin/src/components/ReleaseActionOptions.d.ts +9 -0
- package/dist/admin/src/components/ReleaseListCell.d.ts +28 -0
- package/dist/admin/src/components/ReleaseModal.d.ts +17 -0
- package/dist/admin/src/components/ReleasesPanel.d.ts +3 -0
- package/dist/admin/src/constants.d.ts +76 -0
- package/dist/admin/src/index.d.ts +3 -0
- package/dist/admin/src/modules/hooks.d.ts +7 -0
- package/dist/admin/src/pages/App.d.ts +1 -0
- package/dist/admin/src/pages/PurchaseContentReleases.d.ts +2 -0
- package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +2 -0
- package/dist/admin/src/pages/ReleasesPage.d.ts +8 -0
- package/dist/admin/src/pages/ReleasesSettingsPage.d.ts +1 -0
- package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +181 -0
- package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +39 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/services/release.d.ts +112 -0
- package/dist/admin/src/store/hooks.d.ts +7 -0
- package/dist/admin/src/utils/api.d.ts +6 -0
- package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
- package/dist/admin/src/utils/time.d.ts +10 -0
- package/dist/admin/src/validation/schemas.d.ts +6 -0
- package/dist/server/index.js +843 -636
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +844 -636
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -0
- package/dist/server/src/constants.d.ts +21 -0
- package/dist/server/src/constants.d.ts.map +1 -0
- package/dist/server/src/content-types/index.d.ts +97 -0
- package/dist/server/src/content-types/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/index.d.ts +48 -0
- package/dist/server/src/content-types/release/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release/schema.d.ts +47 -0
- package/dist/server/src/content-types/release/schema.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/index.d.ts +48 -0
- package/dist/server/src/content-types/release-action/index.d.ts.map +1 -0
- package/dist/server/src/content-types/release-action/schema.d.ts +47 -0
- package/dist/server/src/content-types/release-action/schema.d.ts.map +1 -0
- package/dist/server/src/controllers/index.d.ts +25 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -0
- package/dist/server/src/controllers/release-action.d.ts +10 -0
- package/dist/server/src/controllers/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/release.d.ts +18 -0
- package/dist/server/src/controllers/release.d.ts.map +1 -0
- 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 +14 -0
- package/dist/server/src/controllers/validation/release-action.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/release.d.ts +4 -0
- package/dist/server/src/controllers/validation/release.d.ts.map +1 -0
- 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/destroy.d.ts +5 -0
- package/dist/server/src/destroy.d.ts.map +1 -0
- package/dist/server/src/index.d.ts +2115 -0
- package/dist/server/src/index.d.ts.map +1 -0
- 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 +13 -0
- package/dist/server/src/migrations/index.d.ts.map +1 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/register.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts +51 -0
- package/dist/server/src/routes/index.d.ts.map +1 -0
- package/dist/server/src/routes/release-action.d.ts +18 -0
- package/dist/server/src/routes/release-action.d.ts.map +1 -0
- package/dist/server/src/routes/release.d.ts +18 -0
- package/dist/server/src/routes/release.d.ts.map +1 -0
- 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 +1828 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/release-action.d.ts +38 -0
- package/dist/server/src/services/release-action.d.ts.map +1 -0
- package/dist/server/src/services/release.d.ts +31 -0
- package/dist/server/src/services/release.d.ts.map +1 -0
- package/dist/server/src/services/scheduling.d.ts +18 -0
- package/dist/server/src/services/scheduling.d.ts.map +1 -0
- 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 +18 -0
- package/dist/server/src/services/validation.d.ts.map +1 -0
- package/dist/server/src/utils/index.d.ts +35 -0
- package/dist/server/src/utils/index.d.ts.map +1 -0
- package/dist/shared/contracts/release-actions.d.ts +130 -0
- package/dist/shared/contracts/release-actions.d.ts.map +1 -0
- package/dist/shared/contracts/releases.d.ts +184 -0
- package/dist/shared/contracts/releases.d.ts.map +1 -0
- package/dist/shared/contracts/settings.d.ts +39 -0
- package/dist/shared/contracts/settings.d.ts.map +1 -0
- package/dist/shared/types.d.ts +24 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/package.json +34 -39
- package/dist/_chunks/App-dLXY5ei3.js +0 -1353
- package/dist/_chunks/App-dLXY5ei3.js.map +0 -1
- package/dist/_chunks/App-jrh58sXY.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +0 -1
- package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +0 -1
- package/dist/_chunks/en-HrREghh3.js.map +0 -1
- package/dist/_chunks/en-ltT1TlKQ.mjs.map +0 -1
- package/dist/_chunks/index-CVO0Rqdm.js +0 -1336
- package/dist/_chunks/index-CVO0Rqdm.js.map +0 -1
- package/dist/_chunks/index-PiOGBETy.mjs +0 -1315
- package/dist/_chunks/index-PiOGBETy.mjs.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.js
CHANGED
|
@@ -3,7 +3,6 @@ const utils = require("@strapi/utils");
|
|
|
3
3
|
const isEqual = require("lodash/isEqual");
|
|
4
4
|
const lodash = require("lodash");
|
|
5
5
|
const _ = require("lodash/fp");
|
|
6
|
-
const EE = require("@strapi/strapi/dist/utils/ee");
|
|
7
6
|
const nodeSchedule = require("node-schedule");
|
|
8
7
|
const yup = require("yup");
|
|
9
8
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -27,7 +26,6 @@ function _interopNamespace(e) {
|
|
|
27
26
|
}
|
|
28
27
|
const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
|
|
29
28
|
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
30
|
-
const EE__default = /* @__PURE__ */ _interopDefault(EE);
|
|
31
29
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
32
30
|
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
33
31
|
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
@@ -73,21 +71,38 @@ const ACTIONS = [
|
|
|
73
71
|
displayName: "Add an entry to a release",
|
|
74
72
|
uid: "create-action",
|
|
75
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"
|
|
76
91
|
}
|
|
77
92
|
];
|
|
78
93
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
79
94
|
RELEASES_PUBLISH: "releases.publish"
|
|
80
95
|
};
|
|
81
|
-
const getService = (name, { strapi: strapi2 }
|
|
96
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
82
97
|
return strapi2.plugin("content-releases").service(name);
|
|
83
98
|
};
|
|
84
|
-
const
|
|
99
|
+
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi: strapi2 }) => {
|
|
85
100
|
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
86
|
-
const populate = await populateBuilderService(
|
|
87
|
-
const entry = await
|
|
88
|
-
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 });
|
|
89
104
|
};
|
|
90
|
-
const
|
|
105
|
+
const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
91
106
|
try {
|
|
92
107
|
await strapi2.entityValidator.validateEntityCreation(
|
|
93
108
|
strapi2.getModel(contentTypeUid),
|
|
@@ -101,6 +116,42 @@ const getEntryValidStatus = async (contentTypeUid, entry, { strapi: strapi2 } =
|
|
|
101
116
|
return false;
|
|
102
117
|
}
|
|
103
118
|
};
|
|
119
|
+
const getEntry = async ({
|
|
120
|
+
contentType,
|
|
121
|
+
documentId,
|
|
122
|
+
locale,
|
|
123
|
+
populate,
|
|
124
|
+
status = "draft"
|
|
125
|
+
}, { strapi: strapi2 }) => {
|
|
126
|
+
if (documentId) {
|
|
127
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
128
|
+
if (status === "published" && !entry) {
|
|
129
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
130
|
+
}
|
|
131
|
+
return entry;
|
|
132
|
+
}
|
|
133
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
134
|
+
};
|
|
135
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
136
|
+
if (entry.publishedAt) {
|
|
137
|
+
return "published";
|
|
138
|
+
}
|
|
139
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
140
|
+
documentId: entry.documentId,
|
|
141
|
+
locale: entry.locale,
|
|
142
|
+
status: "published",
|
|
143
|
+
fields: ["updatedAt"]
|
|
144
|
+
});
|
|
145
|
+
if (!publishedEntry) {
|
|
146
|
+
return "draft";
|
|
147
|
+
}
|
|
148
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
149
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
150
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
151
|
+
return "modified";
|
|
152
|
+
}
|
|
153
|
+
return "published";
|
|
154
|
+
};
|
|
104
155
|
async function deleteActionsOnDisableDraftAndPublish({
|
|
105
156
|
oldContentTypes,
|
|
106
157
|
contentTypes: contentTypes2
|
|
@@ -122,7 +173,7 @@ async function deleteActionsOnDisableDraftAndPublish({
|
|
|
122
173
|
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
123
174
|
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
124
175
|
if (deletedContentTypes.length) {
|
|
125
|
-
await utils.
|
|
176
|
+
await utils.async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
126
177
|
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
127
178
|
});
|
|
128
179
|
}
|
|
@@ -141,25 +192,27 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
141
192
|
}
|
|
142
193
|
}
|
|
143
194
|
});
|
|
144
|
-
utils.
|
|
195
|
+
utils.async.map(releasesWithoutStatus, async (release2) => {
|
|
145
196
|
const actions = release2.actions;
|
|
146
197
|
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
147
198
|
for (const action of notValidatedActions) {
|
|
148
199
|
if (action.entry) {
|
|
149
|
-
const
|
|
150
|
-
|
|
200
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
201
|
+
{
|
|
202
|
+
contentType: action.contentType,
|
|
203
|
+
documentId: action.entryDocumentId,
|
|
204
|
+
locale: action.locale
|
|
205
|
+
},
|
|
206
|
+
{ strapi }
|
|
207
|
+
);
|
|
208
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
209
|
+
where: {
|
|
210
|
+
id: action.id
|
|
211
|
+
},
|
|
212
|
+
data: {
|
|
213
|
+
isEntryValid: isEntryValid2
|
|
214
|
+
}
|
|
151
215
|
});
|
|
152
|
-
if (populatedEntry) {
|
|
153
|
-
const isEntryValid = getEntryValidStatus(action.contentType, populatedEntry, { strapi });
|
|
154
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
155
|
-
where: {
|
|
156
|
-
id: action.id
|
|
157
|
-
},
|
|
158
|
-
data: {
|
|
159
|
-
isEntryValid
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
216
|
}
|
|
164
217
|
}
|
|
165
218
|
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
@@ -172,7 +225,7 @@ async function migrateIsValidAndStatusReleases() {
|
|
|
172
225
|
}
|
|
173
226
|
}
|
|
174
227
|
});
|
|
175
|
-
utils.
|
|
228
|
+
utils.async.map(publishedReleases, async (release2) => {
|
|
176
229
|
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
177
230
|
where: {
|
|
178
231
|
id: release2.id
|
|
@@ -189,7 +242,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
189
242
|
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
190
243
|
);
|
|
191
244
|
const releasesAffected = /* @__PURE__ */ new Set();
|
|
192
|
-
utils.
|
|
245
|
+
utils.async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
193
246
|
const oldContentType = oldContentTypes[contentTypeUID];
|
|
194
247
|
const contentType = contentTypes2[contentTypeUID];
|
|
195
248
|
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
@@ -202,30 +255,30 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
|
|
|
202
255
|
release: true
|
|
203
256
|
}
|
|
204
257
|
});
|
|
205
|
-
await utils.
|
|
206
|
-
if (action.entry && action.release) {
|
|
207
|
-
const
|
|
208
|
-
|
|
258
|
+
await utils.async.map(actions, async (action) => {
|
|
259
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
260
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
261
|
+
{
|
|
262
|
+
contentType: contentTypeUID,
|
|
263
|
+
documentId: action.entryDocumentId,
|
|
264
|
+
locale: action.locale
|
|
265
|
+
},
|
|
266
|
+
{ strapi }
|
|
267
|
+
);
|
|
268
|
+
releasesAffected.add(action.release.id);
|
|
269
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
270
|
+
where: {
|
|
271
|
+
id: action.id
|
|
272
|
+
},
|
|
273
|
+
data: {
|
|
274
|
+
isEntryValid: isEntryValid2
|
|
275
|
+
}
|
|
209
276
|
});
|
|
210
|
-
if (populatedEntry) {
|
|
211
|
-
const isEntryValid = await getEntryValidStatus(contentTypeUID, populatedEntry, {
|
|
212
|
-
strapi
|
|
213
|
-
});
|
|
214
|
-
releasesAffected.add(action.release.id);
|
|
215
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
216
|
-
where: {
|
|
217
|
-
id: action.id
|
|
218
|
-
},
|
|
219
|
-
data: {
|
|
220
|
-
isEntryValid
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
277
|
}
|
|
225
278
|
});
|
|
226
279
|
}
|
|
227
280
|
}).then(() => {
|
|
228
|
-
utils.
|
|
281
|
+
utils.async.map(releasesAffected, async (releaseId) => {
|
|
229
282
|
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
230
283
|
});
|
|
231
284
|
});
|
|
@@ -277,11 +330,43 @@ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: conte
|
|
|
277
330
|
}
|
|
278
331
|
}
|
|
279
332
|
}
|
|
280
|
-
const
|
|
333
|
+
const addEntryDocumentToReleaseActions = {
|
|
334
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
335
|
+
async up(trx, db) {
|
|
336
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
337
|
+
if (!hasTable) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
341
|
+
if (hasPolymorphicColumn) {
|
|
342
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
343
|
+
"strapi_release_actions",
|
|
344
|
+
"entry_document_id"
|
|
345
|
+
);
|
|
346
|
+
if (!hasEntryDocumentIdColumn) {
|
|
347
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
348
|
+
table.string("entry_document_id");
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
352
|
+
utils.async.map(releaseActions, async (action) => {
|
|
353
|
+
const { target_type, target_id } = action;
|
|
354
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
355
|
+
if (entry) {
|
|
356
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
async down() {
|
|
362
|
+
throw new Error("not implemented");
|
|
363
|
+
}
|
|
364
|
+
};
|
|
281
365
|
const register = async ({ strapi: strapi2 }) => {
|
|
282
|
-
if (features
|
|
283
|
-
await strapi2.admin
|
|
284
|
-
strapi2.
|
|
366
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
367
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
368
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
369
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
285
370
|
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
286
371
|
}
|
|
287
372
|
if (strapi2.plugin("graphql")) {
|
|
@@ -290,129 +375,134 @@ const register = async ({ strapi: strapi2 }) => {
|
|
|
290
375
|
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
291
376
|
}
|
|
292
377
|
};
|
|
293
|
-
const
|
|
378
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
379
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
380
|
+
where: {
|
|
381
|
+
actions: {
|
|
382
|
+
contentType,
|
|
383
|
+
entryDocumentId: entry.documentId,
|
|
384
|
+
locale: entry.locale
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
389
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
390
|
+
where: {
|
|
391
|
+
contentType,
|
|
392
|
+
entryDocumentId: entry.documentId,
|
|
393
|
+
locale: entry.locale
|
|
394
|
+
},
|
|
395
|
+
data: {
|
|
396
|
+
isEntryValid: entryStatus
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
for (const release2 of releases) {
|
|
400
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
404
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
405
|
+
where: {
|
|
406
|
+
actions: params
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
410
|
+
where: params
|
|
411
|
+
});
|
|
412
|
+
for (const release2 of releases) {
|
|
413
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
417
|
+
if (ctx.action !== "delete") {
|
|
418
|
+
return next();
|
|
419
|
+
}
|
|
420
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
421
|
+
return next();
|
|
422
|
+
}
|
|
423
|
+
const contentType = ctx.contentType.uid;
|
|
424
|
+
const { documentId, locale } = ctx.params;
|
|
425
|
+
const result = await next();
|
|
426
|
+
if (!result) {
|
|
427
|
+
return result;
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
431
|
+
contentType,
|
|
432
|
+
entryDocumentId: documentId,
|
|
433
|
+
...locale !== "*" && { locale }
|
|
434
|
+
});
|
|
435
|
+
} catch (error) {
|
|
436
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
437
|
+
error
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
441
|
+
};
|
|
442
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
443
|
+
if (ctx.action !== "update") {
|
|
444
|
+
return next();
|
|
445
|
+
}
|
|
446
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
447
|
+
return next();
|
|
448
|
+
}
|
|
449
|
+
const contentType = ctx.contentType.uid;
|
|
450
|
+
const result = await next();
|
|
451
|
+
if (!result) {
|
|
452
|
+
return result;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
458
|
+
error
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return result;
|
|
462
|
+
};
|
|
463
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
464
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
465
|
+
where: {
|
|
466
|
+
actions: params
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
470
|
+
where: params
|
|
471
|
+
});
|
|
472
|
+
for (const release2 of releases) {
|
|
473
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
294
476
|
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
295
|
-
if (features
|
|
477
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
296
478
|
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
297
479
|
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
298
480
|
);
|
|
299
481
|
strapi2.db.lifecycles.subscribe({
|
|
300
482
|
models: contentTypesWithDraftAndPublish,
|
|
301
|
-
async afterDelete(event) {
|
|
302
|
-
try {
|
|
303
|
-
const { model, result } = event;
|
|
304
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
305
|
-
const { id } = result;
|
|
306
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
307
|
-
where: {
|
|
308
|
-
actions: {
|
|
309
|
-
target_type: model.uid,
|
|
310
|
-
target_id: id
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
315
|
-
where: {
|
|
316
|
-
target_type: model.uid,
|
|
317
|
-
target_id: id
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
for (const release2 of releases) {
|
|
321
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
} catch (error) {
|
|
325
|
-
strapi2.log.error("Error while deleting release actions after entry delete", { error });
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
/**
|
|
329
|
-
* deleteMany hook doesn't return the deleted entries ids
|
|
330
|
-
* so we need to fetch them before deleting the entries to save the ids on our state
|
|
331
|
-
*/
|
|
332
|
-
async beforeDeleteMany(event) {
|
|
333
|
-
const { model, params } = event;
|
|
334
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
335
|
-
const { where } = params;
|
|
336
|
-
const entriesToDelete = await strapi2.db.query(model.uid).findMany({ select: ["id"], where });
|
|
337
|
-
event.state.entriesToDelete = entriesToDelete;
|
|
338
|
-
}
|
|
339
|
-
},
|
|
340
483
|
/**
|
|
341
|
-
*
|
|
342
|
-
* We make this only after deleteMany is succesfully executed to avoid errors
|
|
484
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
343
485
|
*/
|
|
344
486
|
async afterDeleteMany(event) {
|
|
345
487
|
try {
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
target_id: {
|
|
354
|
-
$in: entriesToDelete.map(
|
|
355
|
-
(entry) => entry.id
|
|
356
|
-
)
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
362
|
-
where: {
|
|
363
|
-
target_type: model.uid,
|
|
364
|
-
target_id: {
|
|
365
|
-
$in: entriesToDelete.map((entry) => entry.id)
|
|
366
|
-
}
|
|
367
|
-
}
|
|
488
|
+
const model = strapi2.getModel(event.model.uid);
|
|
489
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
490
|
+
const { where } = event.params;
|
|
491
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
492
|
+
contentType: model.uid,
|
|
493
|
+
locale: where?.locale ?? null,
|
|
494
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
368
495
|
});
|
|
369
|
-
for (const release2 of releases) {
|
|
370
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
371
|
-
}
|
|
372
496
|
}
|
|
373
497
|
} catch (error) {
|
|
374
498
|
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
375
499
|
error
|
|
376
500
|
});
|
|
377
501
|
}
|
|
378
|
-
},
|
|
379
|
-
async afterUpdate(event) {
|
|
380
|
-
try {
|
|
381
|
-
const { model, result } = event;
|
|
382
|
-
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
383
|
-
const isEntryValid = await getEntryValidStatus(
|
|
384
|
-
model.uid,
|
|
385
|
-
result,
|
|
386
|
-
{
|
|
387
|
-
strapi: strapi2
|
|
388
|
-
}
|
|
389
|
-
);
|
|
390
|
-
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
391
|
-
where: {
|
|
392
|
-
target_type: model.uid,
|
|
393
|
-
target_id: result.id
|
|
394
|
-
},
|
|
395
|
-
data: {
|
|
396
|
-
isEntryValid
|
|
397
|
-
}
|
|
398
|
-
});
|
|
399
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
400
|
-
where: {
|
|
401
|
-
actions: {
|
|
402
|
-
target_type: model.uid,
|
|
403
|
-
target_id: result.id
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
for (const release2 of releases) {
|
|
408
|
-
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
} catch (error) {
|
|
412
|
-
strapi2.log.error("Error while updating release actions after entry update", { error });
|
|
413
|
-
}
|
|
414
502
|
}
|
|
415
503
|
});
|
|
504
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
505
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
416
506
|
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
417
507
|
strapi2.log.error(
|
|
418
508
|
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
@@ -420,7 +510,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
420
510
|
throw err;
|
|
421
511
|
});
|
|
422
512
|
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
423
|
-
strapi2.webhookStore.addAllowedEvent(key, value);
|
|
513
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
424
514
|
});
|
|
425
515
|
}
|
|
426
516
|
};
|
|
@@ -504,15 +594,13 @@ const schema = {
|
|
|
504
594
|
enum: ["publish", "unpublish"],
|
|
505
595
|
required: true
|
|
506
596
|
},
|
|
507
|
-
entry: {
|
|
508
|
-
type: "relation",
|
|
509
|
-
relation: "morphToOne",
|
|
510
|
-
configurable: false
|
|
511
|
-
},
|
|
512
597
|
contentType: {
|
|
513
598
|
type: "string",
|
|
514
599
|
required: true
|
|
515
600
|
},
|
|
601
|
+
entryDocumentId: {
|
|
602
|
+
type: "string"
|
|
603
|
+
},
|
|
516
604
|
locale: {
|
|
517
605
|
type: "string"
|
|
518
606
|
},
|
|
@@ -534,18 +622,6 @@ const contentTypes = {
|
|
|
534
622
|
release: release$1,
|
|
535
623
|
"release-action": releaseAction$1
|
|
536
624
|
};
|
|
537
|
-
const getGroupName = (queryValue) => {
|
|
538
|
-
switch (queryValue) {
|
|
539
|
-
case "contentType":
|
|
540
|
-
return "contentType.displayName";
|
|
541
|
-
case "action":
|
|
542
|
-
return "type";
|
|
543
|
-
case "locale":
|
|
544
|
-
return ___default.default.getOr("No locale", "locale.name");
|
|
545
|
-
default:
|
|
546
|
-
return "contentType.displayName";
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
625
|
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
550
626
|
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
551
627
|
strapi2.eventHub.emit(event, {
|
|
@@ -554,93 +630,32 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
554
630
|
release: release2
|
|
555
631
|
});
|
|
556
632
|
};
|
|
557
|
-
const publishSingleTypeAction = async (uid, actionType, entryId) => {
|
|
558
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
559
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
560
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
561
|
-
const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
|
|
562
|
-
try {
|
|
563
|
-
if (actionType === "publish") {
|
|
564
|
-
await entityManagerService.publish(entry, uid);
|
|
565
|
-
} else {
|
|
566
|
-
await entityManagerService.unpublish(entry, uid);
|
|
567
|
-
}
|
|
568
|
-
} catch (error) {
|
|
569
|
-
if (error instanceof utils.errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
|
|
570
|
-
;
|
|
571
|
-
else {
|
|
572
|
-
throw error;
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
|
|
577
|
-
const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
|
|
578
|
-
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
579
|
-
const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
|
|
580
|
-
const entriesToPublish = await strapi2.entityService.findMany(uid, {
|
|
581
|
-
filters: {
|
|
582
|
-
id: {
|
|
583
|
-
$in: entriesToPublishIds
|
|
584
|
-
}
|
|
585
|
-
},
|
|
586
|
-
populate
|
|
587
|
-
});
|
|
588
|
-
const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
|
|
589
|
-
filters: {
|
|
590
|
-
id: {
|
|
591
|
-
$in: entriestoUnpublishIds
|
|
592
|
-
}
|
|
593
|
-
},
|
|
594
|
-
populate
|
|
595
|
-
});
|
|
596
|
-
if (entriesToPublish.length > 0) {
|
|
597
|
-
await entityManagerService.publishMany(entriesToPublish, uid);
|
|
598
|
-
}
|
|
599
|
-
if (entriesToUnpublish.length > 0) {
|
|
600
|
-
await entityManagerService.unpublishMany(entriesToUnpublish, uid);
|
|
601
|
-
}
|
|
602
|
-
};
|
|
603
633
|
const getFormattedActions = async (releaseId) => {
|
|
604
634
|
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
605
635
|
where: {
|
|
606
636
|
release: {
|
|
607
637
|
id: releaseId
|
|
608
638
|
}
|
|
609
|
-
},
|
|
610
|
-
populate: {
|
|
611
|
-
entry: {
|
|
612
|
-
fields: ["id"]
|
|
613
|
-
}
|
|
614
639
|
}
|
|
615
640
|
});
|
|
616
641
|
if (actions.length === 0) {
|
|
617
642
|
throw new utils.errors.ValidationError("No entries to publish");
|
|
618
643
|
}
|
|
619
|
-
const
|
|
620
|
-
const singleTypeActions = [];
|
|
644
|
+
const formattedActions = {};
|
|
621
645
|
for (const action of actions) {
|
|
622
646
|
const contentTypeUid = action.contentType;
|
|
623
|
-
if (
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
if (action.type === "publish") {
|
|
631
|
-
collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
|
|
632
|
-
} else {
|
|
633
|
-
collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
|
|
634
|
-
}
|
|
635
|
-
} else {
|
|
636
|
-
singleTypeActions.push({
|
|
637
|
-
uid: contentTypeUid,
|
|
638
|
-
action: action.type,
|
|
639
|
-
id: action.entry.id
|
|
640
|
-
});
|
|
647
|
+
if (!formattedActions[contentTypeUid]) {
|
|
648
|
+
formattedActions[contentTypeUid] = {
|
|
649
|
+
publish: [],
|
|
650
|
+
unpublish: []
|
|
651
|
+
};
|
|
641
652
|
}
|
|
653
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
654
|
+
documentId: action.entryDocumentId,
|
|
655
|
+
locale: action.locale
|
|
656
|
+
});
|
|
642
657
|
}
|
|
643
|
-
return
|
|
658
|
+
return formattedActions;
|
|
644
659
|
};
|
|
645
660
|
return {
|
|
646
661
|
async create(releaseData, { user }) {
|
|
@@ -655,7 +670,7 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
655
670
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
656
671
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
657
672
|
]);
|
|
658
|
-
const release2 = await strapi2.
|
|
673
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
659
674
|
data: {
|
|
660
675
|
...releaseWithCreatorFields,
|
|
661
676
|
status: "empty"
|
|
@@ -669,107 +684,28 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
669
684
|
return release2;
|
|
670
685
|
},
|
|
671
686
|
async findOne(id, query = {}) {
|
|
672
|
-
const
|
|
673
|
-
|
|
687
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
688
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
689
|
+
...dbQuery,
|
|
690
|
+
where: { id }
|
|
674
691
|
});
|
|
675
692
|
return release2;
|
|
676
693
|
},
|
|
677
694
|
findPage(query) {
|
|
678
|
-
|
|
679
|
-
|
|
695
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
696
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
697
|
+
...dbQuery,
|
|
680
698
|
populate: {
|
|
681
699
|
actions: {
|
|
682
|
-
// @ts-expect-error Ignore missing properties
|
|
683
700
|
count: true
|
|
684
701
|
}
|
|
685
702
|
}
|
|
686
703
|
});
|
|
687
704
|
},
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
}
|
|
693
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
694
|
-
where: {
|
|
695
|
-
actions: {
|
|
696
|
-
target_type: contentTypeUid,
|
|
697
|
-
target_id: {
|
|
698
|
-
$in: entries
|
|
699
|
-
}
|
|
700
|
-
},
|
|
701
|
-
releasedAt: {
|
|
702
|
-
$null: true
|
|
703
|
-
}
|
|
704
|
-
},
|
|
705
|
-
populate: {
|
|
706
|
-
// Filter the action to get only the content type entry
|
|
707
|
-
actions: {
|
|
708
|
-
where: {
|
|
709
|
-
target_type: contentTypeUid,
|
|
710
|
-
target_id: {
|
|
711
|
-
$in: entries
|
|
712
|
-
}
|
|
713
|
-
},
|
|
714
|
-
populate: {
|
|
715
|
-
entry: {
|
|
716
|
-
select: ["id"]
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
});
|
|
722
|
-
return releases.map((release2) => {
|
|
723
|
-
if (release2.actions?.length) {
|
|
724
|
-
const actionsForEntry = release2.actions;
|
|
725
|
-
delete release2.actions;
|
|
726
|
-
return {
|
|
727
|
-
...release2,
|
|
728
|
-
actions: actionsForEntry
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
return release2;
|
|
732
|
-
});
|
|
733
|
-
},
|
|
734
|
-
async findManyWithoutContentTypeEntryAttached(contentTypeUid, entryId) {
|
|
735
|
-
const releasesRelated = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
736
|
-
where: {
|
|
737
|
-
releasedAt: {
|
|
738
|
-
$null: true
|
|
739
|
-
},
|
|
740
|
-
actions: {
|
|
741
|
-
target_type: contentTypeUid,
|
|
742
|
-
target_id: entryId
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
});
|
|
746
|
-
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
747
|
-
where: {
|
|
748
|
-
$or: [
|
|
749
|
-
{
|
|
750
|
-
id: {
|
|
751
|
-
$notIn: releasesRelated.map((release2) => release2.id)
|
|
752
|
-
}
|
|
753
|
-
},
|
|
754
|
-
{
|
|
755
|
-
actions: null
|
|
756
|
-
}
|
|
757
|
-
],
|
|
758
|
-
releasedAt: {
|
|
759
|
-
$null: true
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
});
|
|
763
|
-
return releases.map((release2) => {
|
|
764
|
-
if (release2.actions?.length) {
|
|
765
|
-
const [actionForEntry] = release2.actions;
|
|
766
|
-
delete release2.actions;
|
|
767
|
-
return {
|
|
768
|
-
...release2,
|
|
769
|
-
action: actionForEntry
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
return release2;
|
|
705
|
+
findMany(query) {
|
|
706
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
707
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
708
|
+
...dbQuery
|
|
773
709
|
});
|
|
774
710
|
},
|
|
775
711
|
async update(id, releaseData, { user }) {
|
|
@@ -784,19 +720,15 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
784
720
|
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
785
721
|
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
786
722
|
]);
|
|
787
|
-
const release2 = await strapi2.
|
|
723
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
788
724
|
if (!release2) {
|
|
789
725
|
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
790
726
|
}
|
|
791
727
|
if (release2.releasedAt) {
|
|
792
728
|
throw new utils.errors.ValidationError("Release already published");
|
|
793
729
|
}
|
|
794
|
-
const updatedRelease = await strapi2.
|
|
795
|
-
|
|
796
|
-
* The type returned from the entity service: Partial<Input<"plugin::content-releases.release">>
|
|
797
|
-
* is not compatible with the type we are passing here: UpdateRelease.Request['body']
|
|
798
|
-
*/
|
|
799
|
-
// @ts-expect-error see above
|
|
730
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
731
|
+
where: { id },
|
|
800
732
|
data: releaseWithCreatorFields
|
|
801
733
|
});
|
|
802
734
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -809,130 +741,6 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
809
741
|
strapi2.telemetry.send("didUpdateContentRelease");
|
|
810
742
|
return updatedRelease;
|
|
811
743
|
},
|
|
812
|
-
async createAction(releaseId, action) {
|
|
813
|
-
const { validateEntryContentType, validateUniqueEntry } = getService("release-validation", {
|
|
814
|
-
strapi: strapi2
|
|
815
|
-
});
|
|
816
|
-
await Promise.all([
|
|
817
|
-
validateEntryContentType(action.entry.contentType),
|
|
818
|
-
validateUniqueEntry(releaseId, action)
|
|
819
|
-
]);
|
|
820
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId);
|
|
821
|
-
if (!release2) {
|
|
822
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
823
|
-
}
|
|
824
|
-
if (release2.releasedAt) {
|
|
825
|
-
throw new utils.errors.ValidationError("Release already published");
|
|
826
|
-
}
|
|
827
|
-
const { entry, type } = action;
|
|
828
|
-
const populatedEntry = await getPopulatedEntry(entry.contentType, entry.id, { strapi: strapi2 });
|
|
829
|
-
const isEntryValid = await getEntryValidStatus(entry.contentType, populatedEntry, { strapi: strapi2 });
|
|
830
|
-
const releaseAction2 = await strapi2.entityService.create(RELEASE_ACTION_MODEL_UID, {
|
|
831
|
-
data: {
|
|
832
|
-
type,
|
|
833
|
-
contentType: entry.contentType,
|
|
834
|
-
locale: entry.locale,
|
|
835
|
-
isEntryValid,
|
|
836
|
-
entry: {
|
|
837
|
-
id: entry.id,
|
|
838
|
-
__type: entry.contentType,
|
|
839
|
-
__pivot: { field: "entry" }
|
|
840
|
-
},
|
|
841
|
-
release: releaseId
|
|
842
|
-
},
|
|
843
|
-
populate: { release: { fields: ["id"] }, entry: { fields: ["id"] } }
|
|
844
|
-
});
|
|
845
|
-
this.updateReleaseStatus(releaseId);
|
|
846
|
-
return releaseAction2;
|
|
847
|
-
},
|
|
848
|
-
async findActions(releaseId, query) {
|
|
849
|
-
const release2 = await strapi2.entityService.findOne(RELEASE_MODEL_UID, releaseId, {
|
|
850
|
-
fields: ["id"]
|
|
851
|
-
});
|
|
852
|
-
if (!release2) {
|
|
853
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
854
|
-
}
|
|
855
|
-
return strapi2.entityService.findPage(RELEASE_ACTION_MODEL_UID, {
|
|
856
|
-
...query,
|
|
857
|
-
populate: {
|
|
858
|
-
entry: {
|
|
859
|
-
populate: "*"
|
|
860
|
-
}
|
|
861
|
-
},
|
|
862
|
-
filters: {
|
|
863
|
-
release: releaseId
|
|
864
|
-
}
|
|
865
|
-
});
|
|
866
|
-
},
|
|
867
|
-
async countActions(query) {
|
|
868
|
-
return strapi2.entityService.count(RELEASE_ACTION_MODEL_UID, query);
|
|
869
|
-
},
|
|
870
|
-
async groupActions(actions, groupBy) {
|
|
871
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
872
|
-
if (!acc.includes(action.contentType)) {
|
|
873
|
-
acc.push(action.contentType);
|
|
874
|
-
}
|
|
875
|
-
return acc;
|
|
876
|
-
}, []);
|
|
877
|
-
const allReleaseContentTypesDictionary = await this.getContentTypesDataForActions(
|
|
878
|
-
contentTypeUids
|
|
879
|
-
);
|
|
880
|
-
const allLocalesDictionary = await this.getLocalesDataForActions();
|
|
881
|
-
const formattedData = actions.map((action) => {
|
|
882
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
883
|
-
return {
|
|
884
|
-
...action,
|
|
885
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
886
|
-
contentType: {
|
|
887
|
-
displayName,
|
|
888
|
-
mainFieldValue: action.entry[mainField],
|
|
889
|
-
uid: action.contentType
|
|
890
|
-
}
|
|
891
|
-
};
|
|
892
|
-
});
|
|
893
|
-
const groupName = getGroupName(groupBy);
|
|
894
|
-
return ___default.default.groupBy(groupName)(formattedData);
|
|
895
|
-
},
|
|
896
|
-
async getLocalesDataForActions() {
|
|
897
|
-
if (!strapi2.plugin("i18n")) {
|
|
898
|
-
return {};
|
|
899
|
-
}
|
|
900
|
-
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
901
|
-
return allLocales.reduce((acc, locale) => {
|
|
902
|
-
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
903
|
-
return acc;
|
|
904
|
-
}, {});
|
|
905
|
-
},
|
|
906
|
-
async getContentTypesDataForActions(contentTypesUids) {
|
|
907
|
-
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
908
|
-
const contentTypesData = {};
|
|
909
|
-
for (const contentTypeUid of contentTypesUids) {
|
|
910
|
-
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
911
|
-
uid: contentTypeUid
|
|
912
|
-
});
|
|
913
|
-
contentTypesData[contentTypeUid] = {
|
|
914
|
-
mainField: contentTypeConfig.settings.mainField,
|
|
915
|
-
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
return contentTypesData;
|
|
919
|
-
},
|
|
920
|
-
getContentTypeModelsFromActions(actions) {
|
|
921
|
-
const contentTypeUids = actions.reduce((acc, action) => {
|
|
922
|
-
if (!acc.includes(action.contentType)) {
|
|
923
|
-
acc.push(action.contentType);
|
|
924
|
-
}
|
|
925
|
-
return acc;
|
|
926
|
-
}, []);
|
|
927
|
-
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
928
|
-
(acc, contentTypeUid) => {
|
|
929
|
-
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
930
|
-
return acc;
|
|
931
|
-
},
|
|
932
|
-
{}
|
|
933
|
-
);
|
|
934
|
-
return contentTypeModelsMap;
|
|
935
|
-
},
|
|
936
744
|
async getAllComponents() {
|
|
937
745
|
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
938
746
|
const components = await contentManagerComponentsService.findAllComponents();
|
|
@@ -946,10 +754,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
946
754
|
return componentsMap;
|
|
947
755
|
},
|
|
948
756
|
async delete(releaseId) {
|
|
949
|
-
const release2 = await strapi2.
|
|
757
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
758
|
+
where: { id: releaseId },
|
|
950
759
|
populate: {
|
|
951
760
|
actions: {
|
|
952
|
-
|
|
761
|
+
select: ["id"]
|
|
953
762
|
}
|
|
954
763
|
}
|
|
955
764
|
});
|
|
@@ -967,7 +776,11 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
967
776
|
}
|
|
968
777
|
}
|
|
969
778
|
});
|
|
970
|
-
await strapi2.
|
|
779
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
780
|
+
where: {
|
|
781
|
+
id: releaseId
|
|
782
|
+
}
|
|
783
|
+
});
|
|
971
784
|
});
|
|
972
785
|
if (release2.scheduledAt) {
|
|
973
786
|
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
@@ -993,22 +806,19 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
993
806
|
}
|
|
994
807
|
try {
|
|
995
808
|
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
996
|
-
const
|
|
997
|
-
|
|
809
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
810
|
+
await strapi2.db.transaction(
|
|
811
|
+
async () => Promise.all(
|
|
812
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
813
|
+
const contentType = contentTypeUid;
|
|
814
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
815
|
+
return Promise.all([
|
|
816
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
817
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
818
|
+
]);
|
|
819
|
+
})
|
|
820
|
+
)
|
|
998
821
|
);
|
|
999
|
-
await strapi2.db.transaction(async () => {
|
|
1000
|
-
for (const { uid, action, id } of singleTypeActions) {
|
|
1001
|
-
await publishSingleTypeAction(uid, action, id);
|
|
1002
|
-
}
|
|
1003
|
-
for (const contentTypeUid of Object.keys(collectionTypeActions)) {
|
|
1004
|
-
const uid = contentTypeUid;
|
|
1005
|
-
await publishCollectionTypeAction(
|
|
1006
|
-
uid,
|
|
1007
|
-
collectionTypeActions[uid].entriesToPublishIds,
|
|
1008
|
-
collectionTypeActions[uid].entriesToUnpublishIds
|
|
1009
|
-
);
|
|
1010
|
-
}
|
|
1011
|
-
});
|
|
1012
822
|
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1013
823
|
where: {
|
|
1014
824
|
id: releaseId
|
|
@@ -1038,13 +848,226 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1038
848
|
};
|
|
1039
849
|
}
|
|
1040
850
|
});
|
|
1041
|
-
if (error) {
|
|
1042
|
-
throw error;
|
|
851
|
+
if (error instanceof Error) {
|
|
852
|
+
throw error;
|
|
853
|
+
}
|
|
854
|
+
return release2;
|
|
855
|
+
},
|
|
856
|
+
async updateReleaseStatus(releaseId) {
|
|
857
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
858
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
859
|
+
releaseActionService.countActions({
|
|
860
|
+
filters: {
|
|
861
|
+
release: releaseId
|
|
862
|
+
}
|
|
863
|
+
}),
|
|
864
|
+
releaseActionService.countActions({
|
|
865
|
+
filters: {
|
|
866
|
+
release: releaseId,
|
|
867
|
+
isEntryValid: false
|
|
868
|
+
}
|
|
869
|
+
})
|
|
870
|
+
]);
|
|
871
|
+
if (totalActions > 0) {
|
|
872
|
+
if (invalidActions > 0) {
|
|
873
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
874
|
+
where: {
|
|
875
|
+
id: releaseId
|
|
876
|
+
},
|
|
877
|
+
data: {
|
|
878
|
+
status: "blocked"
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
883
|
+
where: {
|
|
884
|
+
id: releaseId
|
|
885
|
+
},
|
|
886
|
+
data: {
|
|
887
|
+
status: "ready"
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
892
|
+
where: {
|
|
893
|
+
id: releaseId
|
|
894
|
+
},
|
|
895
|
+
data: {
|
|
896
|
+
status: "empty"
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
};
|
|
902
|
+
const getGroupName = (queryValue) => {
|
|
903
|
+
switch (queryValue) {
|
|
904
|
+
case "contentType":
|
|
905
|
+
return "contentType.displayName";
|
|
906
|
+
case "type":
|
|
907
|
+
return "type";
|
|
908
|
+
case "locale":
|
|
909
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
910
|
+
default:
|
|
911
|
+
return "contentType.displayName";
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
915
|
+
const getLocalesDataForActions = async () => {
|
|
916
|
+
if (!strapi2.plugin("i18n")) {
|
|
917
|
+
return {};
|
|
918
|
+
}
|
|
919
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
920
|
+
return allLocales.reduce((acc, locale) => {
|
|
921
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
922
|
+
return acc;
|
|
923
|
+
}, {});
|
|
924
|
+
};
|
|
925
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
926
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
927
|
+
const contentTypesData = {};
|
|
928
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
929
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
930
|
+
uid: contentTypeUid
|
|
931
|
+
});
|
|
932
|
+
contentTypesData[contentTypeUid] = {
|
|
933
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
934
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
return contentTypesData;
|
|
938
|
+
};
|
|
939
|
+
return {
|
|
940
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
941
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
942
|
+
strapi: strapi2
|
|
943
|
+
});
|
|
944
|
+
await Promise.all([
|
|
945
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
946
|
+
validateUniqueEntry(releaseId, action)
|
|
947
|
+
]);
|
|
948
|
+
const model = strapi2.contentType(action.contentType);
|
|
949
|
+
if (model.kind === "singleType") {
|
|
950
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
951
|
+
if (!document) {
|
|
952
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
953
|
+
}
|
|
954
|
+
action.entryDocumentId = document.documentId;
|
|
955
|
+
}
|
|
956
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
957
|
+
if (!release2) {
|
|
958
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
959
|
+
}
|
|
960
|
+
if (release2.releasedAt) {
|
|
961
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
962
|
+
}
|
|
963
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
964
|
+
{
|
|
965
|
+
contentType: action.contentType,
|
|
966
|
+
documentId: action.entryDocumentId,
|
|
967
|
+
locale: action.locale
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
strapi: strapi2
|
|
971
|
+
}
|
|
972
|
+
) : true;
|
|
973
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
974
|
+
data: {
|
|
975
|
+
...action,
|
|
976
|
+
release: release2.id,
|
|
977
|
+
isEntryValid: actionStatus
|
|
978
|
+
},
|
|
979
|
+
populate: { release: { select: ["id"] } }
|
|
980
|
+
});
|
|
981
|
+
if (!disableUpdateReleaseStatus) {
|
|
982
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
1043
983
|
}
|
|
1044
|
-
return
|
|
984
|
+
return releaseAction2;
|
|
1045
985
|
},
|
|
1046
|
-
async
|
|
1047
|
-
const
|
|
986
|
+
async findPage(releaseId, query) {
|
|
987
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
988
|
+
where: { id: releaseId },
|
|
989
|
+
select: ["id"]
|
|
990
|
+
});
|
|
991
|
+
if (!release2) {
|
|
992
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
993
|
+
}
|
|
994
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
995
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
996
|
+
...dbQuery,
|
|
997
|
+
where: {
|
|
998
|
+
release: releaseId
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
1002
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
1003
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1004
|
+
const entry = await getEntry(
|
|
1005
|
+
{
|
|
1006
|
+
contentType: action.contentType,
|
|
1007
|
+
documentId: action.entryDocumentId,
|
|
1008
|
+
locale: action.locale,
|
|
1009
|
+
populate,
|
|
1010
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
1011
|
+
},
|
|
1012
|
+
{ strapi: strapi2 }
|
|
1013
|
+
);
|
|
1014
|
+
return {
|
|
1015
|
+
...action,
|
|
1016
|
+
entry,
|
|
1017
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1018
|
+
};
|
|
1019
|
+
});
|
|
1020
|
+
return {
|
|
1021
|
+
results: actionsWithEntry,
|
|
1022
|
+
pagination
|
|
1023
|
+
};
|
|
1024
|
+
},
|
|
1025
|
+
async groupActions(actions, groupBy) {
|
|
1026
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1027
|
+
if (!acc.includes(action.contentType)) {
|
|
1028
|
+
acc.push(action.contentType);
|
|
1029
|
+
}
|
|
1030
|
+
return acc;
|
|
1031
|
+
}, []);
|
|
1032
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1033
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1034
|
+
const formattedData = actions.map((action) => {
|
|
1035
|
+
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1036
|
+
return {
|
|
1037
|
+
...action,
|
|
1038
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1039
|
+
contentType: {
|
|
1040
|
+
displayName,
|
|
1041
|
+
mainFieldValue: action.entry[mainField],
|
|
1042
|
+
uid: action.contentType
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
});
|
|
1046
|
+
const groupName = getGroupName(groupBy);
|
|
1047
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
1048
|
+
},
|
|
1049
|
+
getContentTypeModelsFromActions(actions) {
|
|
1050
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1051
|
+
if (!acc.includes(action.contentType)) {
|
|
1052
|
+
acc.push(action.contentType);
|
|
1053
|
+
}
|
|
1054
|
+
return acc;
|
|
1055
|
+
}, []);
|
|
1056
|
+
const contentTypeModelsMap = contentTypeUids.reduce(
|
|
1057
|
+
(acc, contentTypeUid) => {
|
|
1058
|
+
acc[contentTypeUid] = strapi2.getModel(contentTypeUid);
|
|
1059
|
+
return acc;
|
|
1060
|
+
},
|
|
1061
|
+
{}
|
|
1062
|
+
);
|
|
1063
|
+
return contentTypeModelsMap;
|
|
1064
|
+
},
|
|
1065
|
+
async countActions(query) {
|
|
1066
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1067
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1068
|
+
},
|
|
1069
|
+
async update(actionId, releaseId, update) {
|
|
1070
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1048
1071
|
where: {
|
|
1049
1072
|
id: actionId,
|
|
1050
1073
|
release: {
|
|
@@ -1053,17 +1076,42 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1053
1076
|
$null: true
|
|
1054
1077
|
}
|
|
1055
1078
|
}
|
|
1056
|
-
}
|
|
1057
|
-
data: update
|
|
1079
|
+
}
|
|
1058
1080
|
});
|
|
1059
|
-
if (!
|
|
1081
|
+
if (!action) {
|
|
1060
1082
|
throw new utils.errors.NotFoundError(
|
|
1061
1083
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1062
1084
|
);
|
|
1063
1085
|
}
|
|
1086
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1087
|
+
{
|
|
1088
|
+
contentType: action.contentType,
|
|
1089
|
+
documentId: action.entryDocumentId,
|
|
1090
|
+
locale: action.locale
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
strapi: strapi2
|
|
1094
|
+
}
|
|
1095
|
+
) : true;
|
|
1096
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1097
|
+
where: {
|
|
1098
|
+
id: actionId,
|
|
1099
|
+
release: {
|
|
1100
|
+
id: releaseId,
|
|
1101
|
+
releasedAt: {
|
|
1102
|
+
$null: true
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
data: {
|
|
1107
|
+
...update,
|
|
1108
|
+
isEntryValid: actionStatus
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1064
1112
|
return updatedAction;
|
|
1065
1113
|
},
|
|
1066
|
-
async
|
|
1114
|
+
async delete(actionId, releaseId) {
|
|
1067
1115
|
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1068
1116
|
where: {
|
|
1069
1117
|
id: actionId,
|
|
@@ -1080,51 +1128,8 @@ const createReleaseService = ({ strapi: strapi2 }) => {
|
|
|
1080
1128
|
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1081
1129
|
);
|
|
1082
1130
|
}
|
|
1083
|
-
|
|
1131
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1084
1132
|
return deletedAction;
|
|
1085
|
-
},
|
|
1086
|
-
async updateReleaseStatus(releaseId) {
|
|
1087
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
1088
|
-
this.countActions({
|
|
1089
|
-
filters: {
|
|
1090
|
-
release: releaseId
|
|
1091
|
-
}
|
|
1092
|
-
}),
|
|
1093
|
-
this.countActions({
|
|
1094
|
-
filters: {
|
|
1095
|
-
release: releaseId,
|
|
1096
|
-
isEntryValid: false
|
|
1097
|
-
}
|
|
1098
|
-
})
|
|
1099
|
-
]);
|
|
1100
|
-
if (totalActions > 0) {
|
|
1101
|
-
if (invalidActions > 0) {
|
|
1102
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1103
|
-
where: {
|
|
1104
|
-
id: releaseId
|
|
1105
|
-
},
|
|
1106
|
-
data: {
|
|
1107
|
-
status: "blocked"
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
1110
|
-
}
|
|
1111
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1112
|
-
where: {
|
|
1113
|
-
id: releaseId
|
|
1114
|
-
},
|
|
1115
|
-
data: {
|
|
1116
|
-
status: "ready"
|
|
1117
|
-
}
|
|
1118
|
-
});
|
|
1119
|
-
}
|
|
1120
|
-
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
1121
|
-
where: {
|
|
1122
|
-
id: releaseId
|
|
1123
|
-
},
|
|
1124
|
-
data: {
|
|
1125
|
-
status: "empty"
|
|
1126
|
-
}
|
|
1127
|
-
});
|
|
1128
1133
|
}
|
|
1129
1134
|
};
|
|
1130
1135
|
};
|
|
@@ -1136,37 +1141,43 @@ class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
|
1136
1141
|
}
|
|
1137
1142
|
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1138
1143
|
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1139
|
-
const release2 = await strapi2.
|
|
1140
|
-
|
|
1144
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1145
|
+
where: {
|
|
1146
|
+
id: releaseId
|
|
1147
|
+
},
|
|
1148
|
+
populate: {
|
|
1149
|
+
actions: true
|
|
1150
|
+
}
|
|
1141
1151
|
});
|
|
1142
1152
|
if (!release2) {
|
|
1143
1153
|
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1144
1154
|
}
|
|
1145
1155
|
const isEntryInRelease = release2.actions.some(
|
|
1146
|
-
(action) =>
|
|
1156
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1147
1157
|
);
|
|
1148
1158
|
if (isEntryInRelease) {
|
|
1149
1159
|
throw new AlreadyOnReleaseError(
|
|
1150
|
-
`Entry with
|
|
1160
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1151
1161
|
);
|
|
1152
1162
|
}
|
|
1153
1163
|
},
|
|
1154
|
-
|
|
1164
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1155
1165
|
const contentType = strapi2.contentType(contentTypeUid);
|
|
1156
1166
|
if (!contentType) {
|
|
1157
1167
|
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1158
1168
|
}
|
|
1159
|
-
if (!contentType
|
|
1169
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1160
1170
|
throw new utils.errors.ValidationError(
|
|
1161
1171
|
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1162
1172
|
);
|
|
1163
1173
|
}
|
|
1174
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1175
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1176
|
+
}
|
|
1164
1177
|
},
|
|
1165
1178
|
async validatePendingReleasesLimit() {
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
EE__default.default.features.get("cms-content-releases")?.options?.maximumReleases || 3
|
|
1169
|
-
);
|
|
1179
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1180
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1170
1181
|
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1171
1182
|
filters: {
|
|
1172
1183
|
releasedAt: {
|
|
@@ -1179,8 +1190,8 @@ const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
|
1179
1190
|
}
|
|
1180
1191
|
},
|
|
1181
1192
|
async validateUniqueNameForPendingRelease(name, id) {
|
|
1182
|
-
const pendingReleases = await strapi2.
|
|
1183
|
-
|
|
1193
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1194
|
+
where: {
|
|
1184
1195
|
releasedAt: {
|
|
1185
1196
|
$null: true
|
|
1186
1197
|
},
|
|
@@ -1209,7 +1220,7 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1209
1220
|
}
|
|
1210
1221
|
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1211
1222
|
try {
|
|
1212
|
-
await getService("release").publish(releaseId);
|
|
1223
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1213
1224
|
} catch (error) {
|
|
1214
1225
|
}
|
|
1215
1226
|
this.cancel(releaseId);
|
|
@@ -1251,85 +1262,172 @@ const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
|
1251
1262
|
}
|
|
1252
1263
|
};
|
|
1253
1264
|
};
|
|
1265
|
+
const DEFAULT_SETTINGS = {
|
|
1266
|
+
defaultTimezone: null
|
|
1267
|
+
};
|
|
1268
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1269
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1270
|
+
return {
|
|
1271
|
+
async update({ settings: settings2 }) {
|
|
1272
|
+
const store = await getStore();
|
|
1273
|
+
store.set({ key: "settings", value: settings2 });
|
|
1274
|
+
return settings2;
|
|
1275
|
+
},
|
|
1276
|
+
async find() {
|
|
1277
|
+
const store = await getStore();
|
|
1278
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1279
|
+
return {
|
|
1280
|
+
...DEFAULT_SETTINGS,
|
|
1281
|
+
...settings2 || {}
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
};
|
|
1254
1286
|
const services = {
|
|
1255
1287
|
release: createReleaseService,
|
|
1288
|
+
"release-action": createReleaseActionService,
|
|
1256
1289
|
"release-validation": createReleaseValidationService,
|
|
1257
|
-
scheduling: createSchedulingService
|
|
1290
|
+
scheduling: createSchedulingService,
|
|
1291
|
+
settings: createSettingsService
|
|
1258
1292
|
};
|
|
1259
|
-
const RELEASE_SCHEMA =
|
|
1260
|
-
name:
|
|
1261
|
-
scheduledAt:
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
otherwise: yup__namespace.string().nullable()
|
|
1267
|
-
}),
|
|
1268
|
-
timezone: yup__namespace.string().when("isScheduled", {
|
|
1269
|
-
is: true,
|
|
1270
|
-
then: yup__namespace.string().required().nullable(),
|
|
1271
|
-
otherwise: yup__namespace.string().nullable()
|
|
1272
|
-
}),
|
|
1273
|
-
date: yup__namespace.string().when("isScheduled", {
|
|
1274
|
-
is: true,
|
|
1275
|
-
then: yup__namespace.string().required().nullable(),
|
|
1276
|
-
otherwise: yup__namespace.string().nullable()
|
|
1293
|
+
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1294
|
+
name: utils.yup.string().trim().required(),
|
|
1295
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1296
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1297
|
+
is: (value) => value !== null && value !== void 0,
|
|
1298
|
+
then: utils.yup.string().required(),
|
|
1299
|
+
otherwise: utils.yup.string().nullable()
|
|
1277
1300
|
})
|
|
1278
1301
|
}).required().noUnknown();
|
|
1302
|
+
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1303
|
+
contentType: utils.yup.string().required(),
|
|
1304
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1305
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1306
|
+
locale: utils.yup.string().nullable()
|
|
1307
|
+
}).required().noUnknown();
|
|
1279
1308
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1309
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1310
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1311
|
+
);
|
|
1280
1312
|
const releaseController = {
|
|
1281
|
-
|
|
1282
|
-
|
|
1313
|
+
/**
|
|
1314
|
+
* Find releases based on documents attached or not to the release.
|
|
1315
|
+
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1316
|
+
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1317
|
+
*/
|
|
1318
|
+
async findByDocumentAttached(ctx) {
|
|
1319
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1283
1320
|
ability: ctx.state.userAbility,
|
|
1284
1321
|
model: RELEASE_MODEL_UID
|
|
1285
1322
|
});
|
|
1286
1323
|
await permissionsManager.validateQuery(ctx.query);
|
|
1287
1324
|
const releaseService = getService("release", { strapi });
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1325
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1326
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1327
|
+
const model = strapi.getModel(query.contentType);
|
|
1328
|
+
if (model.kind && model.kind === "singleType") {
|
|
1329
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1330
|
+
if (!document) {
|
|
1331
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1332
|
+
}
|
|
1333
|
+
query.entryDocumentId = document.documentId;
|
|
1334
|
+
}
|
|
1335
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1336
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1337
|
+
if (isEntryAttached) {
|
|
1338
|
+
const releases = await releaseService.findMany({
|
|
1339
|
+
where: {
|
|
1340
|
+
releasedAt: null,
|
|
1341
|
+
actions: {
|
|
1342
|
+
contentType,
|
|
1343
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1344
|
+
locale: locale ?? null
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
populate: {
|
|
1303
1348
|
actions: {
|
|
1304
|
-
|
|
1305
|
-
|
|
1349
|
+
fields: ["type"],
|
|
1350
|
+
filters: {
|
|
1351
|
+
contentType,
|
|
1352
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1353
|
+
locale: locale ?? null
|
|
1306
1354
|
}
|
|
1307
1355
|
}
|
|
1308
|
-
}
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
ctx.body = { data: releases };
|
|
1359
|
+
} else {
|
|
1360
|
+
const relatedReleases = await releaseService.findMany({
|
|
1361
|
+
where: {
|
|
1362
|
+
releasedAt: null,
|
|
1363
|
+
actions: {
|
|
1364
|
+
contentType,
|
|
1365
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1366
|
+
locale: locale ?? null
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1309
1369
|
});
|
|
1310
|
-
const
|
|
1370
|
+
const releases = await releaseService.findMany({
|
|
1311
1371
|
where: {
|
|
1372
|
+
$or: [
|
|
1373
|
+
{
|
|
1374
|
+
id: {
|
|
1375
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1376
|
+
}
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
actions: null
|
|
1380
|
+
}
|
|
1381
|
+
],
|
|
1312
1382
|
releasedAt: null
|
|
1313
1383
|
}
|
|
1314
1384
|
});
|
|
1315
|
-
ctx.body = { data
|
|
1385
|
+
ctx.body = { data: releases };
|
|
1316
1386
|
}
|
|
1317
1387
|
},
|
|
1388
|
+
async findPage(ctx) {
|
|
1389
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1390
|
+
ability: ctx.state.userAbility,
|
|
1391
|
+
model: RELEASE_MODEL_UID
|
|
1392
|
+
});
|
|
1393
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1394
|
+
const releaseService = getService("release", { strapi });
|
|
1395
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1396
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1397
|
+
const data = results.map((release2) => {
|
|
1398
|
+
const { actions, ...releaseData } = release2;
|
|
1399
|
+
return {
|
|
1400
|
+
...releaseData,
|
|
1401
|
+
actions: {
|
|
1402
|
+
meta: {
|
|
1403
|
+
count: actions.count
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
});
|
|
1408
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1409
|
+
where: {
|
|
1410
|
+
releasedAt: null
|
|
1411
|
+
}
|
|
1412
|
+
});
|
|
1413
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1414
|
+
},
|
|
1318
1415
|
async findOne(ctx) {
|
|
1319
1416
|
const id = ctx.params.id;
|
|
1320
1417
|
const releaseService = getService("release", { strapi });
|
|
1418
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1321
1419
|
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1322
1420
|
if (!release2) {
|
|
1323
1421
|
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1324
1422
|
}
|
|
1325
|
-
const count = await
|
|
1423
|
+
const count = await releaseActionService.countActions({
|
|
1326
1424
|
filters: {
|
|
1327
1425
|
release: id
|
|
1328
1426
|
}
|
|
1329
1427
|
});
|
|
1330
1428
|
const sanitizedRelease = {
|
|
1331
1429
|
...release2,
|
|
1332
|
-
createdBy: release2.createdBy ? strapi.admin
|
|
1430
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1333
1431
|
};
|
|
1334
1432
|
const data = {
|
|
1335
1433
|
...sanitizedRelease,
|
|
@@ -1342,22 +1440,39 @@ const releaseController = {
|
|
|
1342
1440
|
ctx.body = { data };
|
|
1343
1441
|
},
|
|
1344
1442
|
async mapEntriesToReleases(ctx) {
|
|
1345
|
-
const { contentTypeUid,
|
|
1346
|
-
if (!contentTypeUid || !
|
|
1443
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1444
|
+
if (!contentTypeUid || !documentIds) {
|
|
1347
1445
|
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1348
1446
|
}
|
|
1349
1447
|
const releaseService = getService("release", { strapi });
|
|
1350
|
-
const releasesWithActions = await releaseService.
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1448
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1449
|
+
where: {
|
|
1450
|
+
releasedAt: null,
|
|
1451
|
+
actions: {
|
|
1452
|
+
contentType: contentTypeUid,
|
|
1453
|
+
entryDocumentId: {
|
|
1454
|
+
$in: documentIds
|
|
1455
|
+
},
|
|
1456
|
+
locale
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
populate: {
|
|
1460
|
+
actions: true
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1354
1463
|
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1355
1464
|
(acc, release2) => {
|
|
1356
1465
|
release2.actions.forEach((action) => {
|
|
1357
|
-
if (
|
|
1358
|
-
|
|
1466
|
+
if (action.contentType !== contentTypeUid) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (locale && action.locale !== locale) {
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
if (!acc[action.entryDocumentId]) {
|
|
1473
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1359
1474
|
} else {
|
|
1360
|
-
acc[action.
|
|
1475
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1361
1476
|
}
|
|
1362
1477
|
});
|
|
1363
1478
|
return acc;
|
|
@@ -1374,13 +1489,13 @@ const releaseController = {
|
|
|
1374
1489
|
await validateRelease(releaseArgs);
|
|
1375
1490
|
const releaseService = getService("release", { strapi });
|
|
1376
1491
|
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1377
|
-
const permissionsManager = strapi.admin
|
|
1492
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1378
1493
|
ability: ctx.state.userAbility,
|
|
1379
1494
|
model: RELEASE_MODEL_UID
|
|
1380
1495
|
});
|
|
1381
|
-
ctx.
|
|
1496
|
+
ctx.created({
|
|
1382
1497
|
data: await permissionsManager.sanitizeOutput(release2)
|
|
1383
|
-
};
|
|
1498
|
+
});
|
|
1384
1499
|
},
|
|
1385
1500
|
async update(ctx) {
|
|
1386
1501
|
const user = ctx.state.user;
|
|
@@ -1389,7 +1504,7 @@ const releaseController = {
|
|
|
1389
1504
|
await validateRelease(releaseArgs);
|
|
1390
1505
|
const releaseService = getService("release", { strapi });
|
|
1391
1506
|
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1392
|
-
const permissionsManager = strapi.admin
|
|
1507
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1393
1508
|
ability: ctx.state.userAbility,
|
|
1394
1509
|
model: RELEASE_MODEL_UID
|
|
1395
1510
|
});
|
|
@@ -1406,18 +1521,18 @@ const releaseController = {
|
|
|
1406
1521
|
};
|
|
1407
1522
|
},
|
|
1408
1523
|
async publish(ctx) {
|
|
1409
|
-
const user = ctx.state.user;
|
|
1410
1524
|
const id = ctx.params.id;
|
|
1411
1525
|
const releaseService = getService("release", { strapi });
|
|
1412
|
-
const
|
|
1526
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1527
|
+
const release2 = await releaseService.publish(id);
|
|
1413
1528
|
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1414
|
-
|
|
1529
|
+
releaseActionService.countActions({
|
|
1415
1530
|
filters: {
|
|
1416
1531
|
release: id,
|
|
1417
1532
|
type: "publish"
|
|
1418
1533
|
}
|
|
1419
1534
|
}),
|
|
1420
|
-
|
|
1535
|
+
releaseActionService.countActions({
|
|
1421
1536
|
filters: {
|
|
1422
1537
|
release: id,
|
|
1423
1538
|
type: "unpublish"
|
|
@@ -1435,27 +1550,30 @@ const releaseController = {
|
|
|
1435
1550
|
}
|
|
1436
1551
|
};
|
|
1437
1552
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
}).required(),
|
|
1553
|
+
contentType: utils.yup.string().required(),
|
|
1554
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1555
|
+
locale: utils.yup.string(),
|
|
1442
1556
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1443
1557
|
});
|
|
1444
1558
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1445
1559
|
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1446
1560
|
});
|
|
1561
|
+
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1562
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1563
|
+
});
|
|
1447
1564
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1448
1565
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1566
|
+
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1449
1567
|
const releaseActionController = {
|
|
1450
1568
|
async create(ctx) {
|
|
1451
1569
|
const releaseId = ctx.params.releaseId;
|
|
1452
1570
|
const releaseActionArgs = ctx.request.body;
|
|
1453
1571
|
await validateReleaseAction(releaseActionArgs);
|
|
1454
|
-
const
|
|
1455
|
-
const releaseAction2 = await
|
|
1456
|
-
ctx.
|
|
1572
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1573
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1574
|
+
ctx.created({
|
|
1457
1575
|
data: releaseAction2
|
|
1458
|
-
};
|
|
1576
|
+
});
|
|
1459
1577
|
},
|
|
1460
1578
|
async createMany(ctx) {
|
|
1461
1579
|
const releaseId = ctx.params.releaseId;
|
|
@@ -1463,12 +1581,15 @@ const releaseActionController = {
|
|
|
1463
1581
|
await Promise.all(
|
|
1464
1582
|
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1465
1583
|
);
|
|
1584
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1466
1585
|
const releaseService = getService("release", { strapi });
|
|
1467
1586
|
const releaseActions = await strapi.db.transaction(async () => {
|
|
1468
1587
|
const releaseActions2 = await Promise.all(
|
|
1469
1588
|
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1470
1589
|
try {
|
|
1471
|
-
const action = await
|
|
1590
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1591
|
+
disableUpdateReleaseStatus: true
|
|
1592
|
+
});
|
|
1472
1593
|
return action;
|
|
1473
1594
|
} catch (error) {
|
|
1474
1595
|
if (error instanceof AlreadyOnReleaseError) {
|
|
@@ -1481,43 +1602,54 @@ const releaseActionController = {
|
|
|
1481
1602
|
return releaseActions2;
|
|
1482
1603
|
});
|
|
1483
1604
|
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1484
|
-
|
|
1605
|
+
if (newReleaseActions.length > 0) {
|
|
1606
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1607
|
+
}
|
|
1608
|
+
ctx.created({
|
|
1485
1609
|
data: newReleaseActions,
|
|
1486
1610
|
meta: {
|
|
1487
1611
|
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1488
1612
|
totalEntries: releaseActions.length
|
|
1489
1613
|
}
|
|
1490
|
-
};
|
|
1614
|
+
});
|
|
1491
1615
|
},
|
|
1492
1616
|
async findMany(ctx) {
|
|
1493
1617
|
const releaseId = ctx.params.releaseId;
|
|
1494
|
-
const permissionsManager = strapi.admin
|
|
1618
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1495
1619
|
ability: ctx.state.userAbility,
|
|
1496
1620
|
model: RELEASE_ACTION_MODEL_UID
|
|
1497
1621
|
});
|
|
1622
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1623
|
+
if (ctx.query.groupBy) {
|
|
1624
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1625
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1629
|
+
delete ctx.query.groupBy;
|
|
1498
1630
|
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1499
|
-
const
|
|
1500
|
-
const { results, pagination } = await
|
|
1501
|
-
sort: query.groupBy === "action" ? "type" : query.groupBy,
|
|
1631
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1632
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1502
1633
|
...query
|
|
1503
1634
|
});
|
|
1504
1635
|
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1505
1636
|
if (acc[action.contentType]) {
|
|
1506
1637
|
return acc;
|
|
1507
1638
|
}
|
|
1508
|
-
const contentTypePermissionsManager = strapi.admin
|
|
1639
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1509
1640
|
ability: ctx.state.userAbility,
|
|
1510
1641
|
model: action.contentType
|
|
1511
1642
|
});
|
|
1512
1643
|
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1513
1644
|
return acc;
|
|
1514
1645
|
}, {});
|
|
1515
|
-
const sanitizedResults = await utils.
|
|
1646
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1516
1647
|
...action,
|
|
1517
|
-
entry: await contentTypeOutputSanitizers[action.contentType](action.entry)
|
|
1648
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1518
1649
|
}));
|
|
1519
|
-
const groupedData = await
|
|
1520
|
-
const contentTypes2 =
|
|
1650
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1651
|
+
const contentTypes2 = releaseActionService.getContentTypeModelsFromActions(results);
|
|
1652
|
+
const releaseService = getService("release", { strapi });
|
|
1521
1653
|
const components = await releaseService.getAllComponents();
|
|
1522
1654
|
ctx.body = {
|
|
1523
1655
|
data: groupedData,
|
|
@@ -1533,8 +1665,8 @@ const releaseActionController = {
|
|
|
1533
1665
|
const releaseId = ctx.params.releaseId;
|
|
1534
1666
|
const releaseActionUpdateArgs = ctx.request.body;
|
|
1535
1667
|
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1536
|
-
const
|
|
1537
|
-
const updatedAction = await
|
|
1668
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1669
|
+
const updatedAction = await releaseActionService.update(
|
|
1538
1670
|
actionId,
|
|
1539
1671
|
releaseId,
|
|
1540
1672
|
releaseActionUpdateArgs
|
|
@@ -1546,14 +1678,36 @@ const releaseActionController = {
|
|
|
1546
1678
|
async delete(ctx) {
|
|
1547
1679
|
const actionId = ctx.params.actionId;
|
|
1548
1680
|
const releaseId = ctx.params.releaseId;
|
|
1549
|
-
const
|
|
1550
|
-
const deletedReleaseAction = await
|
|
1681
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1682
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1551
1683
|
ctx.body = {
|
|
1552
1684
|
data: deletedReleaseAction
|
|
1553
1685
|
};
|
|
1554
1686
|
}
|
|
1555
1687
|
};
|
|
1556
|
-
const
|
|
1688
|
+
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1689
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1690
|
+
}).required().noUnknown();
|
|
1691
|
+
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
1692
|
+
const settingsController = {
|
|
1693
|
+
async find(ctx) {
|
|
1694
|
+
const settingsService = getService("settings", { strapi });
|
|
1695
|
+
const settings2 = await settingsService.find();
|
|
1696
|
+
ctx.body = { data: settings2 };
|
|
1697
|
+
},
|
|
1698
|
+
async update(ctx) {
|
|
1699
|
+
const settingsBody = ctx.request.body;
|
|
1700
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1701
|
+
const settingsService = getService("settings", { strapi });
|
|
1702
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1703
|
+
ctx.body = { data: updatedSettings };
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
const controllers = {
|
|
1707
|
+
release: releaseController,
|
|
1708
|
+
"release-action": releaseActionController,
|
|
1709
|
+
settings: settingsController
|
|
1710
|
+
};
|
|
1557
1711
|
const release = {
|
|
1558
1712
|
type: "admin",
|
|
1559
1713
|
routes: [
|
|
@@ -1573,6 +1727,22 @@ const release = {
|
|
|
1573
1727
|
]
|
|
1574
1728
|
}
|
|
1575
1729
|
},
|
|
1730
|
+
{
|
|
1731
|
+
method: "GET",
|
|
1732
|
+
path: "/getByDocumentAttached",
|
|
1733
|
+
handler: "release.findByDocumentAttached",
|
|
1734
|
+
config: {
|
|
1735
|
+
policies: [
|
|
1736
|
+
"admin::isAuthenticatedAdmin",
|
|
1737
|
+
{
|
|
1738
|
+
name: "admin::hasPermissions",
|
|
1739
|
+
config: {
|
|
1740
|
+
actions: ["plugin::content-releases.read"]
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
]
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1576
1746
|
{
|
|
1577
1747
|
method: "POST",
|
|
1578
1748
|
path: "/",
|
|
@@ -1592,7 +1762,7 @@ const release = {
|
|
|
1592
1762
|
{
|
|
1593
1763
|
method: "GET",
|
|
1594
1764
|
path: "/",
|
|
1595
|
-
handler: "release.
|
|
1765
|
+
handler: "release.findPage",
|
|
1596
1766
|
config: {
|
|
1597
1767
|
policies: [
|
|
1598
1768
|
"admin::isAuthenticatedAdmin",
|
|
@@ -1756,13 +1926,50 @@ const releaseAction = {
|
|
|
1756
1926
|
}
|
|
1757
1927
|
]
|
|
1758
1928
|
};
|
|
1929
|
+
const settings = {
|
|
1930
|
+
type: "admin",
|
|
1931
|
+
routes: [
|
|
1932
|
+
{
|
|
1933
|
+
method: "GET",
|
|
1934
|
+
path: "/settings",
|
|
1935
|
+
handler: "settings.find",
|
|
1936
|
+
config: {
|
|
1937
|
+
policies: [
|
|
1938
|
+
"admin::isAuthenticatedAdmin",
|
|
1939
|
+
{
|
|
1940
|
+
name: "admin::hasPermissions",
|
|
1941
|
+
config: {
|
|
1942
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
]
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
{
|
|
1949
|
+
method: "PUT",
|
|
1950
|
+
path: "/settings",
|
|
1951
|
+
handler: "settings.update",
|
|
1952
|
+
config: {
|
|
1953
|
+
policies: [
|
|
1954
|
+
"admin::isAuthenticatedAdmin",
|
|
1955
|
+
{
|
|
1956
|
+
name: "admin::hasPermissions",
|
|
1957
|
+
config: {
|
|
1958
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
]
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
]
|
|
1965
|
+
};
|
|
1759
1966
|
const routes = {
|
|
1967
|
+
settings,
|
|
1760
1968
|
release,
|
|
1761
1969
|
"release-action": releaseAction
|
|
1762
1970
|
};
|
|
1763
|
-
const { features } = require("@strapi/strapi/dist/utils/ee");
|
|
1764
1971
|
const getPlugin = () => {
|
|
1765
|
-
if (features.isEnabled("cms-content-releases")) {
|
|
1972
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
1766
1973
|
return {
|
|
1767
1974
|
register,
|
|
1768
1975
|
bootstrap,
|