@strapi/content-releases 0.0.0-next.39c0188c3aa01bec7b64b948211571d5159e811d → 0.0.0-next.3a1d87a9c3b1d4d89f741c6ecd7f501230fd8d76
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/dist/_chunks/App-CiZCkScI.mjs +1558 -0
- package/dist/_chunks/App-CiZCkScI.mjs.map +1 -0
- package/dist/_chunks/App-SGjO5UPV.js +1578 -0
- package/dist/_chunks/App-SGjO5UPV.js.map +1 -0
- package/dist/_chunks/PurchaseContentReleases--qQepXpP.js +52 -0
- package/dist/_chunks/PurchaseContentReleases--qQepXpP.js.map +1 -0
- package/dist/_chunks/PurchaseContentReleases-D-n-w-st.mjs +52 -0
- package/dist/_chunks/PurchaseContentReleases-D-n-w-st.mjs.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-Cto_NLUd.js +178 -0
- package/dist/_chunks/ReleasesSettingsPage-Cto_NLUd.js.map +1 -0
- package/dist/_chunks/ReleasesSettingsPage-DQT8N3A-.mjs +178 -0
- package/dist/_chunks/ReleasesSettingsPage-DQT8N3A-.mjs.map +1 -0
- package/dist/_chunks/en-BWPPsSH-.js +102 -0
- package/dist/{admin/chunks/en-B2EeDoOz.js.map → _chunks/en-BWPPsSH-.js.map} +1 -1
- package/dist/_chunks/en-D9Q4YW03.mjs +102 -0
- package/dist/_chunks/en-D9Q4YW03.mjs.map +1 -0
- package/dist/_chunks/index-BjvFfTtA.mjs +1386 -0
- package/dist/_chunks/index-BjvFfTtA.mjs.map +1 -0
- package/dist/_chunks/index-CyU534vL.js +1404 -0
- package/dist/_chunks/index-CyU534vL.js.map +1 -0
- package/dist/_chunks/schemas-DBYv9gK8.js +61 -0
- package/dist/_chunks/schemas-DBYv9gK8.js.map +1 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs +44 -0
- package/dist/_chunks/schemas-DdA2ic2U.mjs.map +1 -0
- package/dist/admin/index.js +3 -18
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -13
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/components/ReleaseListCell.d.ts +1 -1
- package/dist/server/index.js +1869 -2165
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1861 -2156
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/destroy.d.ts +1 -1
- package/dist/server/src/destroy.d.ts.map +1 -1
- package/dist/server/src/middlewares/documents.d.ts +1 -1
- package/dist/server/src/middlewares/documents.d.ts.map +1 -1
- package/dist/server/src/services/scheduling.d.ts +1 -1
- package/dist/server/src/services/scheduling.d.ts.map +1 -1
- package/dist/server/src/services/validation.d.ts +1 -1
- package/dist/server/src/services/validation.d.ts.map +1 -1
- package/dist/shared/contracts/release-actions.d.ts +1 -0
- package/dist/shared/contracts/releases.d.ts +1 -0
- package/dist/shared/contracts/settings.d.ts +2 -1
- package/dist/shared/contracts/settings.d.ts.map +1 -1
- package/dist/shared/types.d.ts +1 -0
- package/package.json +11 -14
- package/dist/admin/chunks/App-B9yCdSLJ.js +0 -1866
- package/dist/admin/chunks/App-B9yCdSLJ.js.map +0 -1
- package/dist/admin/chunks/App-CZiJBsId.js +0 -1845
- package/dist/admin/chunks/App-CZiJBsId.js.map +0 -1
- package/dist/admin/chunks/PurchaseContentReleases-BCME5SQU.js +0 -55
- package/dist/admin/chunks/PurchaseContentReleases-BCME5SQU.js.map +0 -1
- package/dist/admin/chunks/PurchaseContentReleases-S1ccDSwp.js +0 -53
- package/dist/admin/chunks/PurchaseContentReleases-S1ccDSwp.js.map +0 -1
- package/dist/admin/chunks/ReleasesSettingsPage-Csq9aGu9.js +0 -206
- package/dist/admin/chunks/ReleasesSettingsPage-Csq9aGu9.js.map +0 -1
- package/dist/admin/chunks/ReleasesSettingsPage-DFVGppsl.js +0 -208
- package/dist/admin/chunks/ReleasesSettingsPage-DFVGppsl.js.map +0 -1
- package/dist/admin/chunks/en-B2EeDoOz.js +0 -101
- package/dist/admin/chunks/en-BzpFfVeO.js +0 -103
- package/dist/admin/chunks/en-BzpFfVeO.js.map +0 -1
- package/dist/admin/chunks/index-1nn-zHX-.js +0 -1657
- package/dist/admin/chunks/index-1nn-zHX-.js.map +0 -1
- package/dist/admin/chunks/index-BexsXldu.js +0 -1618
- package/dist/admin/chunks/index-BexsXldu.js.map +0 -1
- package/dist/admin/chunks/schemas-DMt8h1z-.js +0 -43
- package/dist/admin/chunks/schemas-DMt8h1z-.js.map +0 -1
- package/dist/admin/chunks/schemas-DS7NeFDN.js +0 -65
- package/dist/admin/chunks/schemas-DS7NeFDN.js.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -1,2353 +1,2057 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
const utils = require("@strapi/utils");
|
|
3
|
+
const isEqual = require("lodash/isEqual");
|
|
4
|
+
const lodash = require("lodash");
|
|
5
|
+
const _ = require("lodash/fp");
|
|
6
|
+
const nodeSchedule = require("node-schedule");
|
|
7
|
+
const yup = require("yup");
|
|
8
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
12
12
|
if (e) {
|
|
13
|
-
|
|
14
|
-
if (k !==
|
|
15
|
-
|
|
13
|
+
for (const k in e) {
|
|
14
|
+
if (k !== "default") {
|
|
15
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
16
|
Object.defineProperty(n, k, d.get ? d : {
|
|
17
17
|
enumerable: true,
|
|
18
|
-
get:
|
|
18
|
+
get: () => e[k]
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
-
}
|
|
21
|
+
}
|
|
22
22
|
}
|
|
23
23
|
n.default = e;
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const RELEASE_MODEL_UID =
|
|
30
|
-
const RELEASE_ACTION_MODEL_UID =
|
|
26
|
+
const isEqual__default = /* @__PURE__ */ _interopDefault(isEqual);
|
|
27
|
+
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
28
|
+
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
|
29
|
+
const RELEASE_MODEL_UID = "plugin::content-releases.release";
|
|
30
|
+
const RELEASE_ACTION_MODEL_UID = "plugin::content-releases.release-action";
|
|
31
31
|
const ACTIONS = [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
32
|
+
{
|
|
33
|
+
section: "plugins",
|
|
34
|
+
displayName: "Read",
|
|
35
|
+
uid: "read",
|
|
36
|
+
pluginName: "content-releases"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
section: "plugins",
|
|
40
|
+
displayName: "Create",
|
|
41
|
+
uid: "create",
|
|
42
|
+
pluginName: "content-releases"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
section: "plugins",
|
|
46
|
+
displayName: "Edit",
|
|
47
|
+
uid: "update",
|
|
48
|
+
pluginName: "content-releases"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
section: "plugins",
|
|
52
|
+
displayName: "Delete",
|
|
53
|
+
uid: "delete",
|
|
54
|
+
pluginName: "content-releases"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
section: "plugins",
|
|
58
|
+
displayName: "Publish",
|
|
59
|
+
uid: "publish",
|
|
60
|
+
pluginName: "content-releases"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
section: "plugins",
|
|
64
|
+
displayName: "Remove an entry from a release",
|
|
65
|
+
uid: "delete-action",
|
|
66
|
+
pluginName: "content-releases"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
section: "plugins",
|
|
70
|
+
displayName: "Add an entry to a release",
|
|
71
|
+
uid: "create-action",
|
|
72
|
+
pluginName: "content-releases"
|
|
73
|
+
},
|
|
74
|
+
// Settings
|
|
75
|
+
{
|
|
76
|
+
uid: "settings.read",
|
|
77
|
+
section: "settings",
|
|
78
|
+
displayName: "Read",
|
|
79
|
+
category: "content releases",
|
|
80
|
+
subCategory: "options",
|
|
81
|
+
pluginName: "content-releases"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
uid: "settings.update",
|
|
85
|
+
section: "settings",
|
|
86
|
+
displayName: "Edit",
|
|
87
|
+
category: "content releases",
|
|
88
|
+
subCategory: "options",
|
|
89
|
+
pluginName: "content-releases"
|
|
90
|
+
}
|
|
91
91
|
];
|
|
92
92
|
const ALLOWED_WEBHOOK_EVENTS = {
|
|
93
|
-
|
|
93
|
+
RELEASES_PUBLISH: "releases.publish"
|
|
94
94
|
};
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return strapi1.plugin('content-releases').service(name);
|
|
95
|
+
const getService = (name, { strapi: strapi2 }) => {
|
|
96
|
+
return strapi2.plugin("content-releases").service(name);
|
|
98
97
|
};
|
|
99
|
-
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
contentType,
|
|
105
|
-
documentId,
|
|
106
|
-
locale,
|
|
107
|
-
populate
|
|
108
|
-
}, {
|
|
109
|
-
strapi: strapi1
|
|
110
|
-
});
|
|
111
|
-
return isEntryValid(contentType, entry, {
|
|
112
|
-
strapi: strapi1
|
|
113
|
-
});
|
|
98
|
+
const getDraftEntryValidStatus = async ({ contentType, documentId, locale }, { strapi: strapi2 }) => {
|
|
99
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
100
|
+
const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();
|
|
101
|
+
const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi: strapi2 });
|
|
102
|
+
return isEntryValid(contentType, entry, { strapi: strapi2 });
|
|
114
103
|
};
|
|
115
|
-
const isEntryValid = async (contentTypeUid, entry, { strapi:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
104
|
+
const isEntryValid = async (contentTypeUid, entry, { strapi: strapi2 }) => {
|
|
105
|
+
try {
|
|
106
|
+
await strapi2.entityValidator.validateEntityCreation(
|
|
107
|
+
strapi2.getModel(contentTypeUid),
|
|
108
|
+
entry,
|
|
109
|
+
void 0,
|
|
110
|
+
// @ts-expect-error - FIXME: entity here is unnecessary
|
|
111
|
+
entry
|
|
112
|
+
);
|
|
113
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
114
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
115
|
+
populate: "stageRequiredToPublish"
|
|
116
|
+
});
|
|
117
|
+
if (workflow?.stageRequiredToPublish) {
|
|
118
|
+
return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;
|
|
130
119
|
}
|
|
120
|
+
return true;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
131
124
|
};
|
|
132
|
-
const getEntry = async ({
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return strapi1.documents(contentType).findOne({
|
|
144
|
-
documentId,
|
|
145
|
-
locale,
|
|
146
|
-
populate,
|
|
147
|
-
status: 'draft'
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
return entry;
|
|
125
|
+
const getEntry = async ({
|
|
126
|
+
contentType,
|
|
127
|
+
documentId,
|
|
128
|
+
locale,
|
|
129
|
+
populate,
|
|
130
|
+
status = "draft"
|
|
131
|
+
}, { strapi: strapi2 }) => {
|
|
132
|
+
if (documentId) {
|
|
133
|
+
const entry = await strapi2.documents(contentType).findOne({ documentId, locale, populate, status });
|
|
134
|
+
if (status === "published" && !entry) {
|
|
135
|
+
return strapi2.documents(contentType).findOne({ documentId, locale, populate, status: "draft" });
|
|
151
136
|
}
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
status
|
|
156
|
-
});
|
|
137
|
+
return entry;
|
|
138
|
+
}
|
|
139
|
+
return strapi2.documents(contentType).findFirst({ locale, populate, status });
|
|
157
140
|
};
|
|
158
|
-
const getEntryStatus = async (contentType, entry)=>{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
return 'published';
|
|
141
|
+
const getEntryStatus = async (contentType, entry) => {
|
|
142
|
+
if (entry.publishedAt) {
|
|
143
|
+
return "published";
|
|
144
|
+
}
|
|
145
|
+
const publishedEntry = await strapi.documents(contentType).findOne({
|
|
146
|
+
documentId: entry.documentId,
|
|
147
|
+
locale: entry.locale,
|
|
148
|
+
status: "published",
|
|
149
|
+
fields: ["updatedAt"]
|
|
150
|
+
});
|
|
151
|
+
if (!publishedEntry) {
|
|
152
|
+
return "draft";
|
|
153
|
+
}
|
|
154
|
+
const entryUpdatedAt = new Date(entry.updatedAt).getTime();
|
|
155
|
+
const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();
|
|
156
|
+
if (entryUpdatedAt > publishedEntryUpdatedAt) {
|
|
157
|
+
return "modified";
|
|
158
|
+
}
|
|
159
|
+
return "published";
|
|
179
160
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
161
|
+
async function deleteActionsOnDisableDraftAndPublish({
|
|
162
|
+
oldContentTypes,
|
|
163
|
+
contentTypes: contentTypes2
|
|
164
|
+
}) {
|
|
165
|
+
if (!oldContentTypes) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
for (const uid in contentTypes2) {
|
|
169
|
+
if (!oldContentTypes[uid]) {
|
|
170
|
+
continue;
|
|
184
171
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const oldContentType = oldContentTypes[uid];
|
|
190
|
-
const contentType = contentTypes[uid];
|
|
191
|
-
if (utils.contentTypes.hasDraftAndPublish(oldContentType) && !utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
192
|
-
await strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({
|
|
193
|
-
contentType: uid
|
|
194
|
-
}).execute();
|
|
195
|
-
}
|
|
172
|
+
const oldContentType = oldContentTypes[uid];
|
|
173
|
+
const contentType = contentTypes2[uid];
|
|
174
|
+
if (utils.contentTypes.hasDraftAndPublish(oldContentType) && !utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
175
|
+
await strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: uid }).execute();
|
|
196
176
|
}
|
|
177
|
+
}
|
|
197
178
|
}
|
|
198
|
-
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes }) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
});
|
|
206
|
-
}
|
|
179
|
+
async function deleteActionsOnDeleteContentType({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
180
|
+
const deletedContentTypes = lodash.difference(lodash.keys(oldContentTypes), lodash.keys(contentTypes2)) ?? [];
|
|
181
|
+
if (deletedContentTypes.length) {
|
|
182
|
+
await utils.async.map(deletedContentTypes, async (deletedContentTypeUID) => {
|
|
183
|
+
return strapi.db?.queryBuilder(RELEASE_ACTION_MODEL_UID).delete().where({ contentType: deletedContentTypeUID }).execute();
|
|
184
|
+
});
|
|
185
|
+
}
|
|
207
186
|
}
|
|
208
187
|
async function migrateIsValidAndStatusReleases() {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
188
|
+
const releasesWithoutStatus = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
189
|
+
where: {
|
|
190
|
+
status: null,
|
|
191
|
+
releasedAt: null
|
|
192
|
+
},
|
|
193
|
+
populate: {
|
|
194
|
+
actions: {
|
|
214
195
|
populate: {
|
|
215
|
-
|
|
216
|
-
populate: {
|
|
217
|
-
entry: true
|
|
218
|
-
}
|
|
219
|
-
}
|
|
196
|
+
entry: true
|
|
220
197
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return getService('release', {
|
|
247
|
-
strapi
|
|
248
|
-
}).updateReleaseStatus(release.id);
|
|
249
|
-
});
|
|
250
|
-
const publishedReleases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
251
|
-
where: {
|
|
252
|
-
status: null,
|
|
253
|
-
releasedAt: {
|
|
254
|
-
$notNull: true
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
utils.async.map(publishedReleases, async (release)=>{
|
|
259
|
-
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
260
|
-
where: {
|
|
261
|
-
id: release.id
|
|
262
|
-
},
|
|
263
|
-
data: {
|
|
264
|
-
status: 'done'
|
|
265
|
-
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
utils.async.map(releasesWithoutStatus, async (release2) => {
|
|
202
|
+
const actions = release2.actions;
|
|
203
|
+
const notValidatedActions = actions.filter((action) => action.isEntryValid === null);
|
|
204
|
+
for (const action of notValidatedActions) {
|
|
205
|
+
if (action.entry) {
|
|
206
|
+
const isEntryValid2 = getDraftEntryValidStatus(
|
|
207
|
+
{
|
|
208
|
+
contentType: action.contentType,
|
|
209
|
+
documentId: action.entryDocumentId,
|
|
210
|
+
locale: action.locale
|
|
211
|
+
},
|
|
212
|
+
{ strapi }
|
|
213
|
+
);
|
|
214
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
215
|
+
where: {
|
|
216
|
+
id: action.id
|
|
217
|
+
},
|
|
218
|
+
data: {
|
|
219
|
+
isEntryValid: isEntryValid2
|
|
220
|
+
}
|
|
266
221
|
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
225
|
+
});
|
|
226
|
+
const publishedReleases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
227
|
+
where: {
|
|
228
|
+
status: null,
|
|
229
|
+
releasedAt: {
|
|
230
|
+
$notNull: true
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
utils.async.map(publishedReleases, async (release2) => {
|
|
235
|
+
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
236
|
+
where: {
|
|
237
|
+
id: release2.id
|
|
238
|
+
},
|
|
239
|
+
data: {
|
|
240
|
+
status: "done"
|
|
241
|
+
}
|
|
267
242
|
});
|
|
243
|
+
});
|
|
268
244
|
}
|
|
269
|
-
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes }) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
}).then(()=>{
|
|
309
|
-
// We need to update the status of the releases affected
|
|
310
|
-
utils.async.map(releasesAffected, async (releaseId)=>{
|
|
311
|
-
return getService('release', {
|
|
312
|
-
strapi
|
|
313
|
-
}).updateReleaseStatus(releaseId);
|
|
245
|
+
async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
246
|
+
if (oldContentTypes !== void 0 && contentTypes2 !== void 0) {
|
|
247
|
+
const contentTypesWithDraftAndPublish = Object.keys(oldContentTypes).filter(
|
|
248
|
+
(uid) => oldContentTypes[uid]?.options?.draftAndPublish
|
|
249
|
+
);
|
|
250
|
+
const releasesAffected = /* @__PURE__ */ new Set();
|
|
251
|
+
utils.async.map(contentTypesWithDraftAndPublish, async (contentTypeUID) => {
|
|
252
|
+
const oldContentType = oldContentTypes[contentTypeUID];
|
|
253
|
+
const contentType = contentTypes2[contentTypeUID];
|
|
254
|
+
if (!isEqual__default.default(oldContentType?.attributes, contentType?.attributes)) {
|
|
255
|
+
const actions = await strapi.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
256
|
+
where: {
|
|
257
|
+
contentType: contentTypeUID
|
|
258
|
+
},
|
|
259
|
+
populate: {
|
|
260
|
+
entry: true,
|
|
261
|
+
release: true
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
await utils.async.map(actions, async (action) => {
|
|
265
|
+
if (action.entry && action.release && action.type === "publish") {
|
|
266
|
+
const isEntryValid2 = await getDraftEntryValidStatus(
|
|
267
|
+
{
|
|
268
|
+
contentType: contentTypeUID,
|
|
269
|
+
documentId: action.entryDocumentId,
|
|
270
|
+
locale: action.locale
|
|
271
|
+
},
|
|
272
|
+
{ strapi }
|
|
273
|
+
);
|
|
274
|
+
releasesAffected.add(action.release.id);
|
|
275
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
276
|
+
where: {
|
|
277
|
+
id: action.id
|
|
278
|
+
},
|
|
279
|
+
data: {
|
|
280
|
+
isEntryValid: isEntryValid2
|
|
281
|
+
}
|
|
314
282
|
});
|
|
283
|
+
}
|
|
315
284
|
});
|
|
316
|
-
|
|
285
|
+
}
|
|
286
|
+
}).then(() => {
|
|
287
|
+
utils.async.map(releasesAffected, async (releaseId) => {
|
|
288
|
+
return getService("release", { strapi }).updateReleaseStatus(releaseId);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
}
|
|
317
292
|
}
|
|
318
|
-
async function disableContentTypeLocalized({ oldContentTypes, contentTypes }) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
293
|
+
async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
294
|
+
if (!oldContentTypes) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
298
|
+
if (!i18nPlugin) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
for (const uid in contentTypes2) {
|
|
302
|
+
if (!oldContentTypes[uid]) {
|
|
303
|
+
continue;
|
|
325
304
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
// if i18N is disabled remove non default locales before sync
|
|
334
|
-
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
335
|
-
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
336
|
-
locale: null
|
|
337
|
-
}).where({
|
|
338
|
-
contentType: uid
|
|
339
|
-
}).execute();
|
|
340
|
-
}
|
|
305
|
+
const oldContentType = oldContentTypes[uid];
|
|
306
|
+
const contentType = contentTypes2[uid];
|
|
307
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
308
|
+
if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
|
|
309
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
310
|
+
locale: null
|
|
311
|
+
}).where({ contentType: uid }).execute();
|
|
341
312
|
}
|
|
313
|
+
}
|
|
342
314
|
}
|
|
343
|
-
async function enableContentTypeLocalized({ oldContentTypes, contentTypes }) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
315
|
+
async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
|
|
316
|
+
if (!oldContentTypes) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const i18nPlugin = strapi.plugin("i18n");
|
|
320
|
+
if (!i18nPlugin) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
for (const uid in contentTypes2) {
|
|
324
|
+
if (!oldContentTypes[uid]) {
|
|
325
|
+
continue;
|
|
350
326
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
361
|
-
const defaultLocale = await getDefaultLocale();
|
|
362
|
-
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
363
|
-
locale: defaultLocale
|
|
364
|
-
}).where({
|
|
365
|
-
contentType: uid
|
|
366
|
-
}).execute();
|
|
367
|
-
}
|
|
327
|
+
const oldContentType = oldContentTypes[uid];
|
|
328
|
+
const contentType = contentTypes2[uid];
|
|
329
|
+
const { isLocalizedContentType } = i18nPlugin.service("content-types");
|
|
330
|
+
const { getDefaultLocale } = i18nPlugin.service("locales");
|
|
331
|
+
if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
|
|
332
|
+
const defaultLocale = await getDefaultLocale();
|
|
333
|
+
await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
|
|
334
|
+
locale: defaultLocale
|
|
335
|
+
}).where({ contentType: uid }).execute();
|
|
368
336
|
}
|
|
337
|
+
}
|
|
369
338
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
const releaseActions = await trx.select('*').from('strapi_release_actions');
|
|
396
|
-
utils.async.map(releaseActions, async (action)=>{
|
|
397
|
-
const { target_type, target_id } = action;
|
|
398
|
-
const entry = await db.query(target_type).findOne({
|
|
399
|
-
where: {
|
|
400
|
-
id: target_id
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
if (entry) {
|
|
404
|
-
await trx('strapi_release_actions').update({
|
|
405
|
-
entry_document_id: entry.documentId
|
|
406
|
-
}).where('id', action.id);
|
|
407
|
-
}
|
|
408
|
-
});
|
|
339
|
+
const addEntryDocumentToReleaseActions = {
|
|
340
|
+
name: "content-releases::5.0.0-add-entry-document-id-to-release-actions",
|
|
341
|
+
async up(trx, db) {
|
|
342
|
+
const hasTable = await trx.schema.hasTable("strapi_release_actions");
|
|
343
|
+
if (!hasTable) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const hasPolymorphicColumn = await trx.schema.hasColumn("strapi_release_actions", "target_id");
|
|
347
|
+
if (hasPolymorphicColumn) {
|
|
348
|
+
const hasEntryDocumentIdColumn = await trx.schema.hasColumn(
|
|
349
|
+
"strapi_release_actions",
|
|
350
|
+
"entry_document_id"
|
|
351
|
+
);
|
|
352
|
+
if (!hasEntryDocumentIdColumn) {
|
|
353
|
+
await trx.schema.alterTable("strapi_release_actions", (table) => {
|
|
354
|
+
table.string("entry_document_id");
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
const releaseActions = await trx.select("*").from("strapi_release_actions");
|
|
358
|
+
utils.async.map(releaseActions, async (action) => {
|
|
359
|
+
const { target_type, target_id } = action;
|
|
360
|
+
const entry = await db.query(target_type).findOne({ where: { id: target_id } });
|
|
361
|
+
if (entry) {
|
|
362
|
+
await trx("strapi_release_actions").update({ entry_document_id: entry.documentId }).where("id", action.id);
|
|
409
363
|
}
|
|
410
|
-
|
|
411
|
-
async down () {
|
|
412
|
-
throw new Error('not implemented');
|
|
364
|
+
});
|
|
413
365
|
}
|
|
366
|
+
},
|
|
367
|
+
async down() {
|
|
368
|
+
throw new Error("not implemented");
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
const register = async ({ strapi: strapi2 }) => {
|
|
372
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
373
|
+
await strapi2.service("admin::permission").actionProvider.registerMany(ACTIONS);
|
|
374
|
+
strapi2.db.migrations.providers.internal.register(addEntryDocumentToReleaseActions);
|
|
375
|
+
strapi2.hook("strapi::content-types.beforeSync").register(disableContentTypeLocalized).register(deleteActionsOnDisableDraftAndPublish);
|
|
376
|
+
strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
|
|
377
|
+
}
|
|
378
|
+
if (strapi2.plugin("graphql")) {
|
|
379
|
+
const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
|
|
380
|
+
graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
|
|
381
|
+
graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
|
|
382
|
+
}
|
|
414
383
|
};
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
384
|
+
const updateActionsStatusAndUpdateReleaseStatus = async (contentType, entry) => {
|
|
385
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
386
|
+
where: {
|
|
387
|
+
releasedAt: null,
|
|
388
|
+
actions: {
|
|
389
|
+
contentType,
|
|
390
|
+
entryDocumentId: entry.documentId,
|
|
391
|
+
locale: entry.locale
|
|
392
|
+
}
|
|
422
393
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
394
|
+
});
|
|
395
|
+
const entryStatus = await isEntryValid(contentType, entry, { strapi });
|
|
396
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).updateMany({
|
|
397
|
+
where: {
|
|
398
|
+
contentType,
|
|
399
|
+
entryDocumentId: entry.documentId,
|
|
400
|
+
locale: entry.locale
|
|
401
|
+
},
|
|
402
|
+
data: {
|
|
403
|
+
isEntryValid: entryStatus
|
|
428
404
|
}
|
|
405
|
+
});
|
|
406
|
+
for (const release2 of releases) {
|
|
407
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
408
|
+
}
|
|
429
409
|
};
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
releasedAt: null,
|
|
435
|
-
actions: {
|
|
436
|
-
contentType,
|
|
437
|
-
entryDocumentId: entry.documentId,
|
|
438
|
-
locale: entry.locale
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
const entryStatus = await isEntryValid(contentType, entry, {
|
|
443
|
-
strapi
|
|
444
|
-
});
|
|
445
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).updateMany({
|
|
446
|
-
where: {
|
|
447
|
-
contentType,
|
|
448
|
-
entryDocumentId: entry.documentId,
|
|
449
|
-
locale: entry.locale
|
|
450
|
-
},
|
|
451
|
-
data: {
|
|
452
|
-
isEntryValid: entryStatus
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
for (const release of releases){
|
|
456
|
-
getService('release', {
|
|
457
|
-
strapi
|
|
458
|
-
}).updateReleaseStatus(release.id);
|
|
410
|
+
const deleteActionsAndUpdateReleaseStatus = async (params) => {
|
|
411
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
412
|
+
where: {
|
|
413
|
+
actions: params
|
|
459
414
|
}
|
|
415
|
+
});
|
|
416
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
417
|
+
where: params
|
|
418
|
+
});
|
|
419
|
+
for (const release2 of releases) {
|
|
420
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
421
|
+
}
|
|
460
422
|
};
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
423
|
+
const deleteActionsOnDelete = async (ctx, next) => {
|
|
424
|
+
if (ctx.action !== "delete") {
|
|
425
|
+
return next();
|
|
426
|
+
}
|
|
427
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
428
|
+
return next();
|
|
429
|
+
}
|
|
430
|
+
const contentType = ctx.contentType.uid;
|
|
431
|
+
const { documentId, locale } = ctx.params;
|
|
432
|
+
const result = await next();
|
|
433
|
+
if (!result) {
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
try {
|
|
437
|
+
deleteActionsAndUpdateReleaseStatus({
|
|
438
|
+
contentType,
|
|
439
|
+
entryDocumentId: documentId,
|
|
440
|
+
...locale !== "*" && { locale }
|
|
466
441
|
});
|
|
467
|
-
|
|
468
|
-
|
|
442
|
+
} catch (error) {
|
|
443
|
+
strapi.log.error("Error while deleting release actions after delete", {
|
|
444
|
+
error
|
|
469
445
|
});
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
strapi
|
|
473
|
-
}).updateReleaseStatus(release.id);
|
|
474
|
-
}
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
475
448
|
};
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (!result) {
|
|
487
|
-
return result;
|
|
488
|
-
}
|
|
489
|
-
try {
|
|
490
|
-
deleteActionsAndUpdateReleaseStatus({
|
|
491
|
-
contentType,
|
|
492
|
-
entryDocumentId: documentId,
|
|
493
|
-
...locale !== '*' && {
|
|
494
|
-
locale
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
} catch (error) {
|
|
498
|
-
strapi.log.error('Error while deleting release actions after delete', {
|
|
499
|
-
error
|
|
500
|
-
});
|
|
501
|
-
}
|
|
449
|
+
const updateActionsOnUpdate = async (ctx, next) => {
|
|
450
|
+
if (ctx.action !== "update") {
|
|
451
|
+
return next();
|
|
452
|
+
}
|
|
453
|
+
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
454
|
+
return next();
|
|
455
|
+
}
|
|
456
|
+
const contentType = ctx.contentType.uid;
|
|
457
|
+
const result = await next();
|
|
458
|
+
if (!result) {
|
|
502
459
|
return result;
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
updateActionsStatusAndUpdateReleaseStatus(contentType, result);
|
|
463
|
+
} catch (error) {
|
|
464
|
+
strapi.log.error("Error while updating release actions after update", {
|
|
465
|
+
error
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
503
469
|
};
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
if (!utils.contentTypes.hasDraftAndPublish(ctx.contentType)) {
|
|
509
|
-
return next();
|
|
470
|
+
const deleteReleasesActionsAndUpdateReleaseStatus = async (params) => {
|
|
471
|
+
const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
472
|
+
where: {
|
|
473
|
+
actions: params
|
|
510
474
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
} catch (error) {
|
|
519
|
-
strapi.log.error('Error while updating release actions after update', {
|
|
520
|
-
error
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
return result;
|
|
475
|
+
});
|
|
476
|
+
await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
477
|
+
where: params
|
|
478
|
+
});
|
|
479
|
+
for (const release2 of releases) {
|
|
480
|
+
getService("release", { strapi }).updateReleaseStatus(release2.id);
|
|
481
|
+
}
|
|
524
482
|
};
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
483
|
+
const bootstrap = async ({ strapi: strapi2 }) => {
|
|
484
|
+
if (strapi2.ee.features.isEnabled("cms-content-releases")) {
|
|
485
|
+
const contentTypesWithDraftAndPublish = Object.keys(strapi2.contentTypes).filter(
|
|
486
|
+
(uid) => strapi2.contentTypes[uid]?.options?.draftAndPublish
|
|
487
|
+
);
|
|
488
|
+
strapi2.db.lifecycles.subscribe({
|
|
489
|
+
models: contentTypesWithDraftAndPublish,
|
|
490
|
+
/**
|
|
491
|
+
* deleteMany is still used outside documents service, for example when deleting a locale
|
|
492
|
+
*/
|
|
493
|
+
async afterDeleteMany(event) {
|
|
494
|
+
try {
|
|
495
|
+
const model = strapi2.getModel(event.model.uid);
|
|
496
|
+
if (model.kind === "collectionType" && model.options?.draftAndPublish) {
|
|
497
|
+
const { where } = event.params;
|
|
498
|
+
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
499
|
+
contentType: model.uid,
|
|
500
|
+
locale: where?.locale ?? null,
|
|
501
|
+
...where?.documentId && { entryDocumentId: where.documentId }
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
} catch (error) {
|
|
505
|
+
strapi2.log.error("Error while deleting release actions after entry deleteMany", {
|
|
506
|
+
error
|
|
507
|
+
});
|
|
530
508
|
}
|
|
509
|
+
}
|
|
531
510
|
});
|
|
532
|
-
|
|
533
|
-
|
|
511
|
+
strapi2.documents.use(deleteActionsOnDelete);
|
|
512
|
+
strapi2.documents.use(updateActionsOnUpdate);
|
|
513
|
+
getService("scheduling", { strapi: strapi2 }).syncFromDatabase().catch((err) => {
|
|
514
|
+
strapi2.log.error(
|
|
515
|
+
"Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling."
|
|
516
|
+
);
|
|
517
|
+
throw err;
|
|
534
518
|
});
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}).updateReleaseStatus(release.id);
|
|
540
|
-
}
|
|
519
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
520
|
+
strapi2.get("webhookStore").addAllowedEvent(key, value);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
541
523
|
};
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
*/ async afterDeleteMany (event) {
|
|
550
|
-
try {
|
|
551
|
-
const model = strapi1.getModel(event.model.uid);
|
|
552
|
-
// @ts-expect-error TODO: lifecycles types looks like are not 100% finished
|
|
553
|
-
if (model.kind === 'collectionType' && model.options?.draftAndPublish) {
|
|
554
|
-
const { where } = event.params;
|
|
555
|
-
deleteReleasesActionsAndUpdateReleaseStatus({
|
|
556
|
-
contentType: model.uid,
|
|
557
|
-
locale: where?.locale ?? null,
|
|
558
|
-
...where?.documentId && {
|
|
559
|
-
entryDocumentId: where.documentId
|
|
560
|
-
}
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
} catch (error) {
|
|
564
|
-
// If an error happens we don't want to block the delete entry flow, but we log the error
|
|
565
|
-
strapi1.log.error('Error while deleting release actions after entry deleteMany', {
|
|
566
|
-
error
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
// We register middleware to handle ReleaseActions when changes on documents are made
|
|
572
|
-
strapi1.documents.use(deleteActionsOnDelete);
|
|
573
|
-
strapi1.documents.use(updateActionsOnUpdate);
|
|
574
|
-
getService('scheduling', {
|
|
575
|
-
strapi: strapi1
|
|
576
|
-
}).syncFromDatabase().catch((err)=>{
|
|
577
|
-
strapi1.log.error('Error while syncing scheduled jobs from the database in the content-releases plugin. This could lead to errors in the releases scheduling.');
|
|
578
|
-
throw err;
|
|
579
|
-
});
|
|
580
|
-
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value])=>{
|
|
581
|
-
strapi1.get('webhookStore').addAllowedEvent(key, value);
|
|
582
|
-
});
|
|
583
|
-
}
|
|
524
|
+
const destroy = async ({ strapi: strapi2 }) => {
|
|
525
|
+
const scheduledJobs = getService("scheduling", {
|
|
526
|
+
strapi: strapi2
|
|
527
|
+
}).getAll();
|
|
528
|
+
for (const [, job] of scheduledJobs) {
|
|
529
|
+
job.cancel();
|
|
530
|
+
}
|
|
584
531
|
};
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
532
|
+
const schema$1 = {
|
|
533
|
+
collectionName: "strapi_releases",
|
|
534
|
+
info: {
|
|
535
|
+
singularName: "release",
|
|
536
|
+
pluralName: "releases",
|
|
537
|
+
displayName: "Release"
|
|
538
|
+
},
|
|
539
|
+
options: {
|
|
540
|
+
draftAndPublish: false
|
|
541
|
+
},
|
|
542
|
+
pluginOptions: {
|
|
543
|
+
"content-manager": {
|
|
544
|
+
visible: false
|
|
545
|
+
},
|
|
546
|
+
"content-type-builder": {
|
|
547
|
+
visible: false
|
|
592
548
|
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
singularName: 'release',
|
|
599
|
-
pluralName: 'releases',
|
|
600
|
-
displayName: 'Release'
|
|
549
|
+
},
|
|
550
|
+
attributes: {
|
|
551
|
+
name: {
|
|
552
|
+
type: "string",
|
|
553
|
+
required: true
|
|
601
554
|
},
|
|
602
|
-
|
|
603
|
-
|
|
555
|
+
releasedAt: {
|
|
556
|
+
type: "datetime"
|
|
604
557
|
},
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
visible: false
|
|
608
|
-
},
|
|
609
|
-
'content-type-builder': {
|
|
610
|
-
visible: false
|
|
611
|
-
}
|
|
558
|
+
scheduledAt: {
|
|
559
|
+
type: "datetime"
|
|
612
560
|
},
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
},
|
|
627
|
-
status: {
|
|
628
|
-
type: 'enumeration',
|
|
629
|
-
enum: [
|
|
630
|
-
'ready',
|
|
631
|
-
'blocked',
|
|
632
|
-
'failed',
|
|
633
|
-
'done',
|
|
634
|
-
'empty'
|
|
635
|
-
],
|
|
636
|
-
required: true
|
|
637
|
-
},
|
|
638
|
-
actions: {
|
|
639
|
-
type: 'relation',
|
|
640
|
-
relation: 'oneToMany',
|
|
641
|
-
target: RELEASE_ACTION_MODEL_UID,
|
|
642
|
-
mappedBy: 'release'
|
|
643
|
-
}
|
|
561
|
+
timezone: {
|
|
562
|
+
type: "string"
|
|
563
|
+
},
|
|
564
|
+
status: {
|
|
565
|
+
type: "enumeration",
|
|
566
|
+
enum: ["ready", "blocked", "failed", "done", "empty"],
|
|
567
|
+
required: true
|
|
568
|
+
},
|
|
569
|
+
actions: {
|
|
570
|
+
type: "relation",
|
|
571
|
+
relation: "oneToMany",
|
|
572
|
+
target: RELEASE_ACTION_MODEL_UID,
|
|
573
|
+
mappedBy: "release"
|
|
644
574
|
}
|
|
575
|
+
}
|
|
645
576
|
};
|
|
646
|
-
|
|
647
577
|
const release$1 = {
|
|
648
|
-
|
|
578
|
+
schema: schema$1
|
|
649
579
|
};
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
580
|
+
const schema = {
|
|
581
|
+
collectionName: "strapi_release_actions",
|
|
582
|
+
info: {
|
|
583
|
+
singularName: "release-action",
|
|
584
|
+
pluralName: "release-actions",
|
|
585
|
+
displayName: "Release Action"
|
|
586
|
+
},
|
|
587
|
+
options: {
|
|
588
|
+
draftAndPublish: false
|
|
589
|
+
},
|
|
590
|
+
pluginOptions: {
|
|
591
|
+
"content-manager": {
|
|
592
|
+
visible: false
|
|
657
593
|
},
|
|
658
|
-
|
|
659
|
-
|
|
594
|
+
"content-type-builder": {
|
|
595
|
+
visible: false
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
attributes: {
|
|
599
|
+
type: {
|
|
600
|
+
type: "enumeration",
|
|
601
|
+
enum: ["publish", "unpublish"],
|
|
602
|
+
required: true
|
|
660
603
|
},
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
},
|
|
665
|
-
'content-type-builder': {
|
|
666
|
-
visible: false
|
|
667
|
-
}
|
|
604
|
+
contentType: {
|
|
605
|
+
type: "string",
|
|
606
|
+
required: true
|
|
668
607
|
},
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
type: 'string'
|
|
684
|
-
},
|
|
685
|
-
locale: {
|
|
686
|
-
type: 'string'
|
|
687
|
-
},
|
|
688
|
-
release: {
|
|
689
|
-
type: 'relation',
|
|
690
|
-
relation: 'manyToOne',
|
|
691
|
-
target: RELEASE_MODEL_UID,
|
|
692
|
-
inversedBy: 'actions'
|
|
693
|
-
},
|
|
694
|
-
isEntryValid: {
|
|
695
|
-
type: 'boolean'
|
|
696
|
-
}
|
|
608
|
+
entryDocumentId: {
|
|
609
|
+
type: "string"
|
|
610
|
+
},
|
|
611
|
+
locale: {
|
|
612
|
+
type: "string"
|
|
613
|
+
},
|
|
614
|
+
release: {
|
|
615
|
+
type: "relation",
|
|
616
|
+
relation: "manyToOne",
|
|
617
|
+
target: RELEASE_MODEL_UID,
|
|
618
|
+
inversedBy: "actions"
|
|
619
|
+
},
|
|
620
|
+
isEntryValid: {
|
|
621
|
+
type: "boolean"
|
|
697
622
|
}
|
|
623
|
+
}
|
|
698
624
|
};
|
|
699
|
-
|
|
700
625
|
const releaseAction$1 = {
|
|
701
|
-
|
|
626
|
+
schema
|
|
702
627
|
};
|
|
703
|
-
|
|
704
628
|
const contentTypes = {
|
|
705
|
-
|
|
706
|
-
|
|
629
|
+
release: release$1,
|
|
630
|
+
"release-action": releaseAction$1
|
|
707
631
|
};
|
|
708
|
-
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
const actions = await strapi.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
722
|
-
where: {
|
|
723
|
-
release: {
|
|
724
|
-
id: releaseId
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
if (actions.length === 0) {
|
|
729
|
-
throw new utils.errors.ValidationError('No entries to publish');
|
|
632
|
+
const createReleaseService = ({ strapi: strapi2 }) => {
|
|
633
|
+
const dispatchWebhook = (event, { isPublished, release: release2, error }) => {
|
|
634
|
+
strapi2.eventHub.emit(event, {
|
|
635
|
+
isPublished,
|
|
636
|
+
error,
|
|
637
|
+
release: release2
|
|
638
|
+
});
|
|
639
|
+
};
|
|
640
|
+
const getFormattedActions = async (releaseId) => {
|
|
641
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
642
|
+
where: {
|
|
643
|
+
release: {
|
|
644
|
+
id: releaseId
|
|
730
645
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
if (actions.length === 0) {
|
|
649
|
+
throw new utils.errors.ValidationError("No entries to publish");
|
|
650
|
+
}
|
|
651
|
+
const formattedActions = {};
|
|
652
|
+
for (const action of actions) {
|
|
653
|
+
const contentTypeUid = action.contentType;
|
|
654
|
+
if (!formattedActions[contentTypeUid]) {
|
|
655
|
+
formattedActions[contentTypeUid] = {
|
|
656
|
+
publish: [],
|
|
657
|
+
unpublish: []
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
formattedActions[contentTypeUid][action.type].push({
|
|
661
|
+
documentId: action.entryDocumentId,
|
|
662
|
+
locale: action.locale
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return formattedActions;
|
|
666
|
+
};
|
|
667
|
+
return {
|
|
668
|
+
async create(releaseData, { user }) {
|
|
669
|
+
const releaseWithCreatorFields = await utils.setCreatorFields({ user })(releaseData);
|
|
670
|
+
const {
|
|
671
|
+
validatePendingReleasesLimit,
|
|
672
|
+
validateUniqueNameForPendingRelease,
|
|
673
|
+
validateScheduledAtIsLaterThanNow
|
|
674
|
+
} = getService("release-validation", { strapi: strapi2 });
|
|
675
|
+
await Promise.all([
|
|
676
|
+
validatePendingReleasesLimit(),
|
|
677
|
+
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),
|
|
678
|
+
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
679
|
+
]);
|
|
680
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).create({
|
|
681
|
+
data: {
|
|
682
|
+
...releaseWithCreatorFields,
|
|
683
|
+
status: "empty"
|
|
746
684
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
});
|
|
821
|
-
if (!release) {
|
|
822
|
-
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
823
|
-
}
|
|
824
|
-
if (release.releasedAt) {
|
|
825
|
-
throw new utils.errors.ValidationError('Release already published');
|
|
826
|
-
}
|
|
827
|
-
const updatedRelease = await strapi.db.query(RELEASE_MODEL_UID).update({
|
|
828
|
-
where: {
|
|
829
|
-
id
|
|
830
|
-
},
|
|
831
|
-
data: releaseWithCreatorFields
|
|
832
|
-
});
|
|
833
|
-
const schedulingService = getService('scheduling', {
|
|
834
|
-
strapi
|
|
835
|
-
});
|
|
836
|
-
if (releaseData.scheduledAt) {
|
|
837
|
-
// set function always cancel the previous job if it exists, so we can call it directly
|
|
838
|
-
await schedulingService.set(id, releaseData.scheduledAt);
|
|
839
|
-
} else if (release.scheduledAt) {
|
|
840
|
-
// When user don't send a scheduledAt and we have one on the release, means that user want to unschedule it
|
|
841
|
-
schedulingService.cancel(id);
|
|
842
|
-
}
|
|
843
|
-
this.updateReleaseStatus(id);
|
|
844
|
-
strapi.telemetry.send('didUpdateContentRelease');
|
|
845
|
-
return updatedRelease;
|
|
846
|
-
},
|
|
847
|
-
async getAllComponents () {
|
|
848
|
-
const contentManagerComponentsService = strapi.plugin('content-manager').service('components');
|
|
849
|
-
const components = await contentManagerComponentsService.findAllComponents();
|
|
850
|
-
const componentsMap = components.reduce((acc, component)=>{
|
|
851
|
-
acc[component.uid] = component;
|
|
852
|
-
return acc;
|
|
853
|
-
}, {});
|
|
854
|
-
return componentsMap;
|
|
685
|
+
});
|
|
686
|
+
if (releaseWithCreatorFields.scheduledAt) {
|
|
687
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
688
|
+
await schedulingService.set(release2.id, release2.scheduledAt);
|
|
689
|
+
}
|
|
690
|
+
strapi2.telemetry.send("didCreateContentRelease");
|
|
691
|
+
return release2;
|
|
692
|
+
},
|
|
693
|
+
async findOne(id, query = {}) {
|
|
694
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query);
|
|
695
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
696
|
+
...dbQuery,
|
|
697
|
+
where: { id }
|
|
698
|
+
});
|
|
699
|
+
return release2;
|
|
700
|
+
},
|
|
701
|
+
findPage(query) {
|
|
702
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
703
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findPage({
|
|
704
|
+
...dbQuery,
|
|
705
|
+
populate: {
|
|
706
|
+
actions: {
|
|
707
|
+
count: true
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
},
|
|
712
|
+
findMany(query) {
|
|
713
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_MODEL_UID, query ?? {});
|
|
714
|
+
return strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
715
|
+
...dbQuery
|
|
716
|
+
});
|
|
717
|
+
},
|
|
718
|
+
async update(id, releaseData, { user }) {
|
|
719
|
+
const releaseWithCreatorFields = await utils.setCreatorFields({ user, isEdition: true })(
|
|
720
|
+
releaseData
|
|
721
|
+
);
|
|
722
|
+
const { validateUniqueNameForPendingRelease, validateScheduledAtIsLaterThanNow } = getService(
|
|
723
|
+
"release-validation",
|
|
724
|
+
{ strapi: strapi2 }
|
|
725
|
+
);
|
|
726
|
+
await Promise.all([
|
|
727
|
+
validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),
|
|
728
|
+
validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt)
|
|
729
|
+
]);
|
|
730
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });
|
|
731
|
+
if (!release2) {
|
|
732
|
+
throw new utils.errors.NotFoundError(`No release found for id ${id}`);
|
|
733
|
+
}
|
|
734
|
+
if (release2.releasedAt) {
|
|
735
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
736
|
+
}
|
|
737
|
+
const updatedRelease = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
738
|
+
where: { id },
|
|
739
|
+
data: releaseWithCreatorFields
|
|
740
|
+
});
|
|
741
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
742
|
+
if (releaseData.scheduledAt) {
|
|
743
|
+
await schedulingService.set(id, releaseData.scheduledAt);
|
|
744
|
+
} else if (release2.scheduledAt) {
|
|
745
|
+
schedulingService.cancel(id);
|
|
746
|
+
}
|
|
747
|
+
this.updateReleaseStatus(id);
|
|
748
|
+
strapi2.telemetry.send("didUpdateContentRelease");
|
|
749
|
+
return updatedRelease;
|
|
750
|
+
},
|
|
751
|
+
async getAllComponents() {
|
|
752
|
+
const contentManagerComponentsService = strapi2.plugin("content-manager").service("components");
|
|
753
|
+
const components = await contentManagerComponentsService.findAllComponents();
|
|
754
|
+
const componentsMap = components.reduce(
|
|
755
|
+
(acc, component) => {
|
|
756
|
+
acc[component.uid] = component;
|
|
757
|
+
return acc;
|
|
855
758
|
},
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
id: {
|
|
881
|
-
$in: release.actions.map((action)=>action.id)
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
});
|
|
885
|
-
await strapi.db.query(RELEASE_MODEL_UID).delete({
|
|
886
|
-
where: {
|
|
887
|
-
id: releaseId
|
|
888
|
-
}
|
|
889
|
-
});
|
|
890
|
-
});
|
|
891
|
-
if (release.scheduledAt) {
|
|
892
|
-
const schedulingService = getService('scheduling', {
|
|
893
|
-
strapi
|
|
894
|
-
});
|
|
895
|
-
await schedulingService.cancel(release.id);
|
|
759
|
+
{}
|
|
760
|
+
);
|
|
761
|
+
return componentsMap;
|
|
762
|
+
},
|
|
763
|
+
async delete(releaseId) {
|
|
764
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
765
|
+
where: { id: releaseId },
|
|
766
|
+
populate: {
|
|
767
|
+
actions: {
|
|
768
|
+
select: ["id"]
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
if (!release2) {
|
|
773
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
774
|
+
}
|
|
775
|
+
if (release2.releasedAt) {
|
|
776
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
777
|
+
}
|
|
778
|
+
await strapi2.db.transaction(async () => {
|
|
779
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({
|
|
780
|
+
where: {
|
|
781
|
+
id: {
|
|
782
|
+
$in: release2.actions.map((action) => action.id)
|
|
896
783
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
await strapi2.db.query(RELEASE_MODEL_UID).delete({
|
|
787
|
+
where: {
|
|
788
|
+
id: releaseId
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
if (release2.scheduledAt) {
|
|
793
|
+
const schedulingService = getService("scheduling", { strapi: strapi2 });
|
|
794
|
+
await schedulingService.cancel(release2.id);
|
|
795
|
+
}
|
|
796
|
+
strapi2.telemetry.send("didDeleteContentRelease");
|
|
797
|
+
return release2;
|
|
798
|
+
},
|
|
799
|
+
async publish(releaseId) {
|
|
800
|
+
const {
|
|
801
|
+
release: release2,
|
|
802
|
+
error
|
|
803
|
+
} = await strapi2.db.transaction(async ({ trx }) => {
|
|
804
|
+
const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
|
|
805
|
+
if (!lockedRelease) {
|
|
806
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
807
|
+
}
|
|
808
|
+
if (lockedRelease.releasedAt) {
|
|
809
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
810
|
+
}
|
|
811
|
+
if (lockedRelease.status === "failed") {
|
|
812
|
+
throw new utils.errors.ValidationError("Release failed to publish");
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
|
|
816
|
+
const formattedActions = await getFormattedActions(releaseId);
|
|
817
|
+
await strapi2.db.transaction(
|
|
818
|
+
async () => Promise.all(
|
|
819
|
+
Object.keys(formattedActions).map(async (contentTypeUid) => {
|
|
820
|
+
const contentType = contentTypeUid;
|
|
821
|
+
const { publish, unpublish } = formattedActions[contentType];
|
|
822
|
+
return Promise.all([
|
|
823
|
+
...publish.map((params) => strapi2.documents(contentType).publish(params)),
|
|
824
|
+
...unpublish.map((params) => strapi2.documents(contentType).unpublish(params))
|
|
825
|
+
]);
|
|
826
|
+
})
|
|
827
|
+
)
|
|
828
|
+
);
|
|
829
|
+
const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
830
|
+
where: {
|
|
831
|
+
id: releaseId
|
|
832
|
+
},
|
|
833
|
+
data: {
|
|
834
|
+
status: "done",
|
|
835
|
+
releasedAt: /* @__PURE__ */ new Date()
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
839
|
+
isPublished: true,
|
|
840
|
+
release: release22
|
|
841
|
+
});
|
|
842
|
+
strapi2.telemetry.send("didPublishContentRelease");
|
|
843
|
+
return { release: release22, error: null };
|
|
844
|
+
} catch (error2) {
|
|
845
|
+
dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
|
|
846
|
+
isPublished: false,
|
|
847
|
+
error: error2
|
|
848
|
+
});
|
|
849
|
+
await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
|
|
850
|
+
status: "failed"
|
|
851
|
+
}).transacting(trx).execute();
|
|
852
|
+
return {
|
|
853
|
+
release: null,
|
|
854
|
+
error: error2
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
});
|
|
858
|
+
if (error instanceof Error) {
|
|
859
|
+
throw error;
|
|
860
|
+
}
|
|
861
|
+
return release2;
|
|
862
|
+
},
|
|
863
|
+
async updateReleaseStatus(releaseId) {
|
|
864
|
+
const releaseActionService = getService("release-action", { strapi: strapi2 });
|
|
865
|
+
const [totalActions, invalidActions] = await Promise.all([
|
|
866
|
+
releaseActionService.countActions({
|
|
867
|
+
filters: {
|
|
868
|
+
release: releaseId
|
|
869
|
+
}
|
|
870
|
+
}),
|
|
871
|
+
releaseActionService.countActions({
|
|
872
|
+
filters: {
|
|
873
|
+
release: releaseId,
|
|
874
|
+
isEntryValid: false
|
|
875
|
+
}
|
|
876
|
+
})
|
|
877
|
+
]);
|
|
878
|
+
if (totalActions > 0) {
|
|
879
|
+
if (invalidActions > 0) {
|
|
880
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
881
|
+
where: {
|
|
882
|
+
id: releaseId
|
|
883
|
+
},
|
|
884
|
+
data: {
|
|
885
|
+
status: "blocked"
|
|
973
886
|
}
|
|
974
|
-
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
890
|
+
where: {
|
|
891
|
+
id: releaseId
|
|
892
|
+
},
|
|
893
|
+
data: {
|
|
894
|
+
status: "ready"
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
return strapi2.db.query(RELEASE_MODEL_UID).update({
|
|
899
|
+
where: {
|
|
900
|
+
id: releaseId
|
|
975
901
|
},
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
strapi
|
|
979
|
-
});
|
|
980
|
-
const [totalActions, invalidActions] = await Promise.all([
|
|
981
|
-
releaseActionService.countActions({
|
|
982
|
-
filters: {
|
|
983
|
-
release: releaseId
|
|
984
|
-
}
|
|
985
|
-
}),
|
|
986
|
-
releaseActionService.countActions({
|
|
987
|
-
filters: {
|
|
988
|
-
release: releaseId,
|
|
989
|
-
isEntryValid: false
|
|
990
|
-
}
|
|
991
|
-
})
|
|
992
|
-
]);
|
|
993
|
-
if (totalActions > 0) {
|
|
994
|
-
if (invalidActions > 0) {
|
|
995
|
-
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
996
|
-
where: {
|
|
997
|
-
id: releaseId
|
|
998
|
-
},
|
|
999
|
-
data: {
|
|
1000
|
-
status: 'blocked'
|
|
1001
|
-
}
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
1005
|
-
where: {
|
|
1006
|
-
id: releaseId
|
|
1007
|
-
},
|
|
1008
|
-
data: {
|
|
1009
|
-
status: 'ready'
|
|
1010
|
-
}
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
|
-
return strapi.db.query(RELEASE_MODEL_UID).update({
|
|
1014
|
-
where: {
|
|
1015
|
-
id: releaseId
|
|
1016
|
-
},
|
|
1017
|
-
data: {
|
|
1018
|
-
status: 'empty'
|
|
1019
|
-
}
|
|
1020
|
-
});
|
|
902
|
+
data: {
|
|
903
|
+
status: "empty"
|
|
1021
904
|
}
|
|
1022
|
-
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
const getGroupName = (queryValue)=>{
|
|
1026
|
-
switch(queryValue){
|
|
1027
|
-
case 'contentType':
|
|
1028
|
-
return 'contentType.displayName';
|
|
1029
|
-
case 'type':
|
|
1030
|
-
return 'type';
|
|
1031
|
-
case 'locale':
|
|
1032
|
-
return _.getOr('No locale', 'locale.name');
|
|
1033
|
-
default:
|
|
1034
|
-
return 'contentType.displayName';
|
|
905
|
+
});
|
|
1035
906
|
}
|
|
907
|
+
};
|
|
1036
908
|
};
|
|
1037
|
-
const
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
909
|
+
const getGroupName = (queryValue) => {
|
|
910
|
+
switch (queryValue) {
|
|
911
|
+
case "contentType":
|
|
912
|
+
return "contentType.displayName";
|
|
913
|
+
case "type":
|
|
914
|
+
return "type";
|
|
915
|
+
case "locale":
|
|
916
|
+
return ___default.default.getOr("No locale", "locale.name");
|
|
917
|
+
default:
|
|
918
|
+
return "contentType.displayName";
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
const createReleaseActionService = ({ strapi: strapi2 }) => {
|
|
922
|
+
const getLocalesDataForActions = async () => {
|
|
923
|
+
if (!strapi2.plugin("i18n")) {
|
|
924
|
+
return {};
|
|
925
|
+
}
|
|
926
|
+
const allLocales = await strapi2.plugin("i18n").service("locales").find() || [];
|
|
927
|
+
return allLocales.reduce((acc, locale) => {
|
|
928
|
+
acc[locale.code] = { name: locale.name, code: locale.code };
|
|
929
|
+
return acc;
|
|
930
|
+
}, {});
|
|
931
|
+
};
|
|
932
|
+
const getContentTypesDataForActions = async (contentTypesUids) => {
|
|
933
|
+
const contentManagerContentTypeService = strapi2.plugin("content-manager").service("content-types");
|
|
934
|
+
const contentTypesData = {};
|
|
935
|
+
for (const contentTypeUid of contentTypesUids) {
|
|
936
|
+
const contentTypeConfig = await contentManagerContentTypeService.findConfiguration({
|
|
937
|
+
uid: contentTypeUid
|
|
938
|
+
});
|
|
939
|
+
contentTypesData[contentTypeUid] = {
|
|
940
|
+
mainField: contentTypeConfig.settings.mainField,
|
|
941
|
+
displayName: strapi2.getModel(contentTypeUid).info.displayName
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
return contentTypesData;
|
|
945
|
+
};
|
|
946
|
+
return {
|
|
947
|
+
async create(releaseId, action, { disableUpdateReleaseStatus = false } = {}) {
|
|
948
|
+
const { validateEntryData, validateUniqueEntry } = getService("release-validation", {
|
|
949
|
+
strapi: strapi2
|
|
950
|
+
});
|
|
951
|
+
await Promise.all([
|
|
952
|
+
validateEntryData(action.contentType, action.entryDocumentId),
|
|
953
|
+
validateUniqueEntry(releaseId, action)
|
|
954
|
+
]);
|
|
955
|
+
const model = strapi2.contentType(action.contentType);
|
|
956
|
+
if (model.kind === "singleType") {
|
|
957
|
+
const document = await strapi2.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
958
|
+
if (!document) {
|
|
959
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
1062
960
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
const document = await strapi.db.query(model.uid).findOne({
|
|
1078
|
-
select: [
|
|
1079
|
-
'documentId'
|
|
1080
|
-
]
|
|
1081
|
-
});
|
|
1082
|
-
if (!document) {
|
|
1083
|
-
throw new utils.errors.NotFoundError(`No entry found for contentType ${action.contentType}`);
|
|
1084
|
-
}
|
|
1085
|
-
action.entryDocumentId = document.documentId;
|
|
1086
|
-
}
|
|
1087
|
-
const release = await strapi.db.query(RELEASE_MODEL_UID).findOne({
|
|
1088
|
-
where: {
|
|
1089
|
-
id: releaseId
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
if (!release) {
|
|
1093
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1094
|
-
}
|
|
1095
|
-
if (release.releasedAt) {
|
|
1096
|
-
throw new utils.errors.ValidationError('Release already published');
|
|
1097
|
-
}
|
|
1098
|
-
// If the action is a publish, check if the entry is valid
|
|
1099
|
-
// If the action is an unpublish, skip the validation
|
|
1100
|
-
const actionStatus = action.type === 'publish' ? await getDraftEntryValidStatus({
|
|
1101
|
-
contentType: action.contentType,
|
|
1102
|
-
documentId: action.entryDocumentId,
|
|
1103
|
-
locale: action.locale
|
|
1104
|
-
}, {
|
|
1105
|
-
strapi
|
|
1106
|
-
}) : true;
|
|
1107
|
-
const releaseAction = await strapi.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
1108
|
-
data: {
|
|
1109
|
-
...action,
|
|
1110
|
-
release: release.id,
|
|
1111
|
-
isEntryValid: actionStatus
|
|
1112
|
-
},
|
|
1113
|
-
populate: {
|
|
1114
|
-
release: {
|
|
1115
|
-
select: [
|
|
1116
|
-
'id'
|
|
1117
|
-
]
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
});
|
|
1121
|
-
if (!disableUpdateReleaseStatus) {
|
|
1122
|
-
getService('release', {
|
|
1123
|
-
strapi
|
|
1124
|
-
}).updateReleaseStatus(release.id);
|
|
1125
|
-
}
|
|
1126
|
-
return releaseAction;
|
|
1127
|
-
},
|
|
1128
|
-
async findPage (releaseId, query) {
|
|
1129
|
-
const release = await strapi.db.query(RELEASE_MODEL_UID).findOne({
|
|
1130
|
-
where: {
|
|
1131
|
-
id: releaseId
|
|
1132
|
-
},
|
|
1133
|
-
select: [
|
|
1134
|
-
'id'
|
|
1135
|
-
]
|
|
1136
|
-
});
|
|
1137
|
-
if (!release) {
|
|
1138
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1139
|
-
}
|
|
1140
|
-
const dbQuery = strapi.get('query-params').transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1141
|
-
const { results: actions, pagination } = await strapi.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
1142
|
-
...dbQuery,
|
|
1143
|
-
where: {
|
|
1144
|
-
release: releaseId
|
|
1145
|
-
}
|
|
1146
|
-
});
|
|
1147
|
-
// For each contentType on the release, we create a custom populate object for nested relations
|
|
1148
|
-
const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');
|
|
1149
|
-
const actionsWithEntry = await utils.async.map(actions, async (action)=>{
|
|
1150
|
-
// @ts-expect-error - Core.Service type is not a function
|
|
1151
|
-
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1152
|
-
const entry = await getEntry({
|
|
1153
|
-
contentType: action.contentType,
|
|
1154
|
-
documentId: action.entryDocumentId,
|
|
1155
|
-
locale: action.locale,
|
|
1156
|
-
populate,
|
|
1157
|
-
status: action.type === 'publish' ? 'draft' : 'published'
|
|
1158
|
-
}, {
|
|
1159
|
-
strapi
|
|
1160
|
-
});
|
|
1161
|
-
return {
|
|
1162
|
-
...action,
|
|
1163
|
-
entry,
|
|
1164
|
-
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1165
|
-
};
|
|
1166
|
-
});
|
|
1167
|
-
return {
|
|
1168
|
-
results: actionsWithEntry,
|
|
1169
|
-
pagination
|
|
1170
|
-
};
|
|
1171
|
-
},
|
|
1172
|
-
async groupActions (actions, groupBy) {
|
|
1173
|
-
const contentTypeUids = actions.reduce((acc, action)=>{
|
|
1174
|
-
if (!acc.includes(action.contentType)) {
|
|
1175
|
-
acc.push(action.contentType);
|
|
1176
|
-
}
|
|
1177
|
-
return acc;
|
|
1178
|
-
}, []);
|
|
1179
|
-
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1180
|
-
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1181
|
-
const formattedData = actions.map((action)=>{
|
|
1182
|
-
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1183
|
-
return {
|
|
1184
|
-
...action,
|
|
1185
|
-
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1186
|
-
contentType: {
|
|
1187
|
-
displayName,
|
|
1188
|
-
mainFieldValue: action.entry[mainField],
|
|
1189
|
-
uid: action.contentType
|
|
1190
|
-
}
|
|
1191
|
-
};
|
|
1192
|
-
});
|
|
1193
|
-
const groupName = getGroupName(groupBy);
|
|
1194
|
-
return _.groupBy(groupName)(formattedData);
|
|
961
|
+
action.entryDocumentId = document.documentId;
|
|
962
|
+
}
|
|
963
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId } });
|
|
964
|
+
if (!release2) {
|
|
965
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
966
|
+
}
|
|
967
|
+
if (release2.releasedAt) {
|
|
968
|
+
throw new utils.errors.ValidationError("Release already published");
|
|
969
|
+
}
|
|
970
|
+
const actionStatus = action.type === "publish" ? await getDraftEntryValidStatus(
|
|
971
|
+
{
|
|
972
|
+
contentType: action.contentType,
|
|
973
|
+
documentId: action.entryDocumentId,
|
|
974
|
+
locale: action.locale
|
|
1195
975
|
},
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
const acc = await accPromise;
|
|
1206
|
-
const contentTypeModel = strapi.getModel(contentTypeUid);
|
|
1207
|
-
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
1208
|
-
populate: 'stageRequiredToPublish'
|
|
1209
|
-
});
|
|
1210
|
-
acc[contentTypeUid] = {
|
|
1211
|
-
...contentTypeModel,
|
|
1212
|
-
hasReviewWorkflow: !!workflow,
|
|
1213
|
-
stageRequiredToPublish: workflow?.stageRequiredToPublish
|
|
1214
|
-
};
|
|
1215
|
-
return acc;
|
|
1216
|
-
}, {});
|
|
1217
|
-
return contentTypeModelsMap;
|
|
976
|
+
{
|
|
977
|
+
strapi: strapi2
|
|
978
|
+
}
|
|
979
|
+
) : true;
|
|
980
|
+
const releaseAction2 = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).create({
|
|
981
|
+
data: {
|
|
982
|
+
...action,
|
|
983
|
+
release: release2.id,
|
|
984
|
+
isEntryValid: actionStatus
|
|
1218
985
|
},
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
986
|
+
populate: { release: { select: ["id"] } }
|
|
987
|
+
});
|
|
988
|
+
if (!disableUpdateReleaseStatus) {
|
|
989
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(release2.id);
|
|
990
|
+
}
|
|
991
|
+
return releaseAction2;
|
|
992
|
+
},
|
|
993
|
+
async findPage(releaseId, query) {
|
|
994
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
995
|
+
where: { id: releaseId },
|
|
996
|
+
select: ["id"]
|
|
997
|
+
});
|
|
998
|
+
if (!release2) {
|
|
999
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1000
|
+
}
|
|
1001
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1002
|
+
const { results: actions, pagination } = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findPage({
|
|
1003
|
+
...dbQuery,
|
|
1004
|
+
where: {
|
|
1005
|
+
release: releaseId
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
|
|
1009
|
+
const actionsWithEntry = await utils.async.map(actions, async (action) => {
|
|
1010
|
+
const populate = await populateBuilderService(action.contentType).populateDeep(Infinity).build();
|
|
1011
|
+
const entry = await getEntry(
|
|
1012
|
+
{
|
|
1013
|
+
contentType: action.contentType,
|
|
1014
|
+
documentId: action.entryDocumentId,
|
|
1015
|
+
locale: action.locale,
|
|
1016
|
+
populate,
|
|
1017
|
+
status: action.type === "publish" ? "draft" : "published"
|
|
1018
|
+
},
|
|
1019
|
+
{ strapi: strapi2 }
|
|
1020
|
+
);
|
|
1021
|
+
return {
|
|
1022
|
+
...action,
|
|
1023
|
+
entry,
|
|
1024
|
+
status: entry ? await getEntryStatus(action.contentType, entry) : null
|
|
1025
|
+
};
|
|
1026
|
+
});
|
|
1027
|
+
return {
|
|
1028
|
+
results: actionsWithEntry,
|
|
1029
|
+
pagination
|
|
1030
|
+
};
|
|
1031
|
+
},
|
|
1032
|
+
async groupActions(actions, groupBy) {
|
|
1033
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1034
|
+
if (!acc.includes(action.contentType)) {
|
|
1035
|
+
acc.push(action.contentType);
|
|
1036
|
+
}
|
|
1037
|
+
return acc;
|
|
1038
|
+
}, []);
|
|
1039
|
+
const allReleaseContentTypesDictionary = await getContentTypesDataForActions(contentTypeUids);
|
|
1040
|
+
const allLocalesDictionary = await getLocalesDataForActions();
|
|
1041
|
+
const formattedData = actions.map((action) => {
|
|
1042
|
+
const { mainField, displayName } = allReleaseContentTypesDictionary[action.contentType];
|
|
1043
|
+
return {
|
|
1044
|
+
...action,
|
|
1045
|
+
locale: action.locale ? allLocalesDictionary[action.locale] : null,
|
|
1046
|
+
contentType: {
|
|
1047
|
+
displayName,
|
|
1048
|
+
mainFieldValue: action.entry[mainField],
|
|
1049
|
+
uid: action.contentType
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
});
|
|
1053
|
+
const groupName = getGroupName(groupBy);
|
|
1054
|
+
return ___default.default.groupBy(groupName)(formattedData);
|
|
1055
|
+
},
|
|
1056
|
+
async getContentTypeModelsFromActions(actions) {
|
|
1057
|
+
const contentTypeUids = actions.reduce((acc, action) => {
|
|
1058
|
+
if (!acc.includes(action.contentType)) {
|
|
1059
|
+
acc.push(action.contentType);
|
|
1060
|
+
}
|
|
1061
|
+
return acc;
|
|
1062
|
+
}, []);
|
|
1063
|
+
const workflowsService = strapi2.plugin("review-workflows").service("workflows");
|
|
1064
|
+
const contentTypeModelsMap = await utils.async.reduce(contentTypeUids)(
|
|
1065
|
+
async (accPromise, contentTypeUid) => {
|
|
1066
|
+
const acc = await accPromise;
|
|
1067
|
+
const contentTypeModel = strapi2.getModel(contentTypeUid);
|
|
1068
|
+
const workflow = await workflowsService.getAssignedWorkflow(contentTypeUid, {
|
|
1069
|
+
populate: "stageRequiredToPublish"
|
|
1070
|
+
});
|
|
1071
|
+
acc[contentTypeUid] = {
|
|
1072
|
+
...contentTypeModel,
|
|
1073
|
+
hasReviewWorkflow: !!workflow,
|
|
1074
|
+
stageRequiredToPublish: workflow?.stageRequiredToPublish
|
|
1075
|
+
};
|
|
1076
|
+
return acc;
|
|
1222
1077
|
},
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1078
|
+
{}
|
|
1079
|
+
);
|
|
1080
|
+
return contentTypeModelsMap;
|
|
1081
|
+
},
|
|
1082
|
+
async countActions(query) {
|
|
1083
|
+
const dbQuery = strapi2.get("query-params").transform(RELEASE_ACTION_MODEL_UID, query ?? {});
|
|
1084
|
+
return strapi2.db.query(RELEASE_ACTION_MODEL_UID).count(dbQuery);
|
|
1085
|
+
},
|
|
1086
|
+
async update(actionId, releaseId, update) {
|
|
1087
|
+
const action = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findOne({
|
|
1088
|
+
where: {
|
|
1089
|
+
id: actionId,
|
|
1090
|
+
release: {
|
|
1091
|
+
id: releaseId,
|
|
1092
|
+
releasedAt: {
|
|
1093
|
+
$null: true
|
|
1237
1094
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
$null: true
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
},
|
|
1255
|
-
data: {
|
|
1256
|
-
...update,
|
|
1257
|
-
isEntryValid: actionStatus
|
|
1258
|
-
}
|
|
1259
|
-
});
|
|
1260
|
-
getService('release', {
|
|
1261
|
-
strapi
|
|
1262
|
-
}).updateReleaseStatus(releaseId);
|
|
1263
|
-
return updatedAction;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
if (!action) {
|
|
1099
|
+
throw new utils.errors.NotFoundError(
|
|
1100
|
+
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
const actionStatus = update.type === "publish" ? await getDraftEntryValidStatus(
|
|
1104
|
+
{
|
|
1105
|
+
contentType: action.contentType,
|
|
1106
|
+
documentId: action.entryDocumentId,
|
|
1107
|
+
locale: action.locale
|
|
1264
1108
|
},
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
});
|
|
1277
|
-
if (!deletedAction) {
|
|
1278
|
-
throw new utils.errors.NotFoundError(`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`);
|
|
1109
|
+
{
|
|
1110
|
+
strapi: strapi2
|
|
1111
|
+
}
|
|
1112
|
+
) : true;
|
|
1113
|
+
const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1114
|
+
where: {
|
|
1115
|
+
id: actionId,
|
|
1116
|
+
release: {
|
|
1117
|
+
id: releaseId,
|
|
1118
|
+
releasedAt: {
|
|
1119
|
+
$null: true
|
|
1279
1120
|
}
|
|
1280
|
-
|
|
1281
|
-
strapi
|
|
1282
|
-
}).updateReleaseStatus(releaseId);
|
|
1283
|
-
return deletedAction;
|
|
1121
|
+
}
|
|
1284
1122
|
},
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
const releasesUpdated = [];
|
|
1304
|
-
await utils.async.map(actions, async (action)=>{
|
|
1305
|
-
const isValid = await getDraftEntryValidStatus({
|
|
1306
|
-
contentType: action.contentType,
|
|
1307
|
-
documentId: action.entryDocumentId,
|
|
1308
|
-
locale: action.locale
|
|
1309
|
-
}, {
|
|
1310
|
-
strapi
|
|
1311
|
-
});
|
|
1312
|
-
await strapi.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1313
|
-
where: {
|
|
1314
|
-
id: action.id
|
|
1315
|
-
},
|
|
1316
|
-
data: {
|
|
1317
|
-
isEntryValid: isValid
|
|
1318
|
-
}
|
|
1319
|
-
});
|
|
1320
|
-
if (!releasesUpdated.includes(action.release.id)) {
|
|
1321
|
-
releasesUpdated.push(action.release.id);
|
|
1322
|
-
}
|
|
1323
|
-
return {
|
|
1324
|
-
id: action.id,
|
|
1325
|
-
isEntryValid: isValid
|
|
1326
|
-
};
|
|
1327
|
-
});
|
|
1328
|
-
if (releasesUpdated.length > 0) {
|
|
1329
|
-
await utils.async.map(releasesUpdated, async (releaseId)=>{
|
|
1330
|
-
await getService('release', {
|
|
1331
|
-
strapi
|
|
1332
|
-
}).updateReleaseStatus(releaseId);
|
|
1333
|
-
});
|
|
1123
|
+
data: {
|
|
1124
|
+
...update,
|
|
1125
|
+
isEntryValid: actionStatus
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1129
|
+
return updatedAction;
|
|
1130
|
+
},
|
|
1131
|
+
async delete(actionId, releaseId) {
|
|
1132
|
+
const deletedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).delete({
|
|
1133
|
+
where: {
|
|
1134
|
+
id: actionId,
|
|
1135
|
+
release: {
|
|
1136
|
+
id: releaseId,
|
|
1137
|
+
releasedAt: {
|
|
1138
|
+
$null: true
|
|
1334
1139
|
}
|
|
1140
|
+
}
|
|
1335
1141
|
}
|
|
1336
|
-
|
|
1142
|
+
});
|
|
1143
|
+
if (!deletedAction) {
|
|
1144
|
+
throw new utils.errors.NotFoundError(
|
|
1145
|
+
`Action with id ${actionId} not found in release with id ${releaseId} or it is already published`
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1149
|
+
return deletedAction;
|
|
1150
|
+
},
|
|
1151
|
+
async validateActionsByContentTypes(contentTypeUids) {
|
|
1152
|
+
const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
|
|
1153
|
+
where: {
|
|
1154
|
+
contentType: {
|
|
1155
|
+
$in: contentTypeUids
|
|
1156
|
+
},
|
|
1157
|
+
// We only want to validate actions that are going to be published
|
|
1158
|
+
type: "publish",
|
|
1159
|
+
release: {
|
|
1160
|
+
releasedAt: {
|
|
1161
|
+
$null: true
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
},
|
|
1165
|
+
populate: { release: true }
|
|
1166
|
+
});
|
|
1167
|
+
const releasesUpdated = [];
|
|
1168
|
+
await utils.async.map(actions, async (action) => {
|
|
1169
|
+
const isValid = await getDraftEntryValidStatus(
|
|
1170
|
+
{
|
|
1171
|
+
contentType: action.contentType,
|
|
1172
|
+
documentId: action.entryDocumentId,
|
|
1173
|
+
locale: action.locale
|
|
1174
|
+
},
|
|
1175
|
+
{ strapi: strapi2 }
|
|
1176
|
+
);
|
|
1177
|
+
await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
|
|
1178
|
+
where: {
|
|
1179
|
+
id: action.id
|
|
1180
|
+
},
|
|
1181
|
+
data: {
|
|
1182
|
+
isEntryValid: isValid
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1185
|
+
if (!releasesUpdated.includes(action.release.id)) {
|
|
1186
|
+
releasesUpdated.push(action.release.id);
|
|
1187
|
+
}
|
|
1188
|
+
return {
|
|
1189
|
+
id: action.id,
|
|
1190
|
+
isEntryValid: isValid
|
|
1191
|
+
};
|
|
1192
|
+
});
|
|
1193
|
+
if (releasesUpdated.length > 0) {
|
|
1194
|
+
await utils.async.map(releasesUpdated, async (releaseId) => {
|
|
1195
|
+
await getService("release", { strapi: strapi2 }).updateReleaseStatus(releaseId);
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
};
|
|
1337
1200
|
};
|
|
1338
|
-
|
|
1339
1201
|
class AlreadyOnReleaseError extends utils.errors.ApplicationError {
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1202
|
+
constructor(message) {
|
|
1203
|
+
super(message);
|
|
1204
|
+
this.name = "AlreadyOnReleaseError";
|
|
1205
|
+
}
|
|
1344
1206
|
}
|
|
1345
|
-
const createReleaseValidationService = ({ strapi })=>({
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
});
|
|
1389
|
-
// Unlimited is a number that will never be reached like 9999
|
|
1390
|
-
if (pendingReleasesCount >= maximumPendingReleases) {
|
|
1391
|
-
throw new utils.errors.ValidationError('You have reached the maximum number of pending releases');
|
|
1392
|
-
}
|
|
1393
|
-
},
|
|
1394
|
-
async validateUniqueNameForPendingRelease (name, id) {
|
|
1395
|
-
const pendingReleases = await strapi.db.query(RELEASE_MODEL_UID).findMany({
|
|
1396
|
-
where: {
|
|
1397
|
-
releasedAt: {
|
|
1398
|
-
$null: true
|
|
1399
|
-
},
|
|
1400
|
-
name,
|
|
1401
|
-
...id && {
|
|
1402
|
-
id: {
|
|
1403
|
-
$ne: id
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
});
|
|
1408
|
-
const isNameUnique = pendingReleases.length === 0;
|
|
1409
|
-
if (!isNameUnique) {
|
|
1410
|
-
throw new utils.errors.ValidationError(`Release with name ${name} already exists`);
|
|
1411
|
-
}
|
|
1412
|
-
},
|
|
1413
|
-
async validateScheduledAtIsLaterThanNow (scheduledAt) {
|
|
1414
|
-
if (scheduledAt && new Date(scheduledAt) <= new Date()) {
|
|
1415
|
-
throw new utils.errors.ValidationError('Scheduled at must be later than now');
|
|
1416
|
-
}
|
|
1207
|
+
const createReleaseValidationService = ({ strapi: strapi2 }) => ({
|
|
1208
|
+
async validateUniqueEntry(releaseId, releaseActionArgs) {
|
|
1209
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({
|
|
1210
|
+
where: {
|
|
1211
|
+
id: releaseId
|
|
1212
|
+
},
|
|
1213
|
+
populate: {
|
|
1214
|
+
actions: true
|
|
1215
|
+
}
|
|
1216
|
+
});
|
|
1217
|
+
if (!release2) {
|
|
1218
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1219
|
+
}
|
|
1220
|
+
const isEntryInRelease = release2.actions.some(
|
|
1221
|
+
(action) => action.entryDocumentId === releaseActionArgs.entryDocumentId && action.contentType === releaseActionArgs.contentType && (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)
|
|
1222
|
+
);
|
|
1223
|
+
if (isEntryInRelease) {
|
|
1224
|
+
throw new AlreadyOnReleaseError(
|
|
1225
|
+
`Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ""} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
validateEntryData(contentTypeUid, entryDocumentId) {
|
|
1230
|
+
const contentType = strapi2.contentType(contentTypeUid);
|
|
1231
|
+
if (!contentType) {
|
|
1232
|
+
throw new utils.errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);
|
|
1233
|
+
}
|
|
1234
|
+
if (!utils.contentTypes.hasDraftAndPublish(contentType)) {
|
|
1235
|
+
throw new utils.errors.ValidationError(
|
|
1236
|
+
`Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
if (contentType.kind === "collectionType" && !entryDocumentId) {
|
|
1240
|
+
throw new utils.errors.ValidationError("Document id is required for collection type");
|
|
1241
|
+
}
|
|
1242
|
+
},
|
|
1243
|
+
async validatePendingReleasesLimit() {
|
|
1244
|
+
const featureCfg = strapi2.ee.features.get("cms-content-releases");
|
|
1245
|
+
const maximumPendingReleases = typeof featureCfg === "object" && featureCfg?.options?.maximumReleases || 3;
|
|
1246
|
+
const [, pendingReleasesCount] = await strapi2.db.query(RELEASE_MODEL_UID).findWithCount({
|
|
1247
|
+
filters: {
|
|
1248
|
+
releasedAt: {
|
|
1249
|
+
$null: true
|
|
1417
1250
|
}
|
|
1251
|
+
}
|
|
1418
1252
|
});
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
}
|
|
1429
|
-
});
|
|
1430
|
-
if (!release) {
|
|
1431
|
-
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1432
|
-
}
|
|
1433
|
-
const job = nodeSchedule.scheduleJob(scheduleDate, async ()=>{
|
|
1434
|
-
try {
|
|
1435
|
-
await getService('release', {
|
|
1436
|
-
strapi
|
|
1437
|
-
}).publish(releaseId);
|
|
1438
|
-
// @TODO: Trigger webhook with success message
|
|
1439
|
-
} catch (error) {
|
|
1440
|
-
// @TODO: Trigger webhook with error message
|
|
1441
|
-
}
|
|
1442
|
-
this.cancel(releaseId);
|
|
1443
|
-
});
|
|
1444
|
-
if (scheduledJobs.has(releaseId)) {
|
|
1445
|
-
this.cancel(releaseId);
|
|
1446
|
-
}
|
|
1447
|
-
scheduledJobs.set(releaseId, job);
|
|
1448
|
-
return scheduledJobs;
|
|
1449
|
-
},
|
|
1450
|
-
cancel (releaseId) {
|
|
1451
|
-
if (scheduledJobs.has(releaseId)) {
|
|
1452
|
-
scheduledJobs.get(releaseId).cancel();
|
|
1453
|
-
scheduledJobs.delete(releaseId);
|
|
1454
|
-
}
|
|
1455
|
-
return scheduledJobs;
|
|
1456
|
-
},
|
|
1457
|
-
getAll () {
|
|
1458
|
-
return scheduledJobs;
|
|
1253
|
+
if (pendingReleasesCount >= maximumPendingReleases) {
|
|
1254
|
+
throw new utils.errors.ValidationError("You have reached the maximum number of pending releases");
|
|
1255
|
+
}
|
|
1256
|
+
},
|
|
1257
|
+
async validateUniqueNameForPendingRelease(name, id) {
|
|
1258
|
+
const pendingReleases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1259
|
+
where: {
|
|
1260
|
+
releasedAt: {
|
|
1261
|
+
$null: true
|
|
1459
1262
|
},
|
|
1460
|
-
|
|
1263
|
+
name,
|
|
1264
|
+
...id && { id: { $ne: id } }
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
const isNameUnique = pendingReleases.length === 0;
|
|
1268
|
+
if (!isNameUnique) {
|
|
1269
|
+
throw new utils.errors.ValidationError(`Release with name ${name} already exists`);
|
|
1270
|
+
}
|
|
1271
|
+
},
|
|
1272
|
+
async validateScheduledAtIsLaterThanNow(scheduledAt) {
|
|
1273
|
+
if (scheduledAt && new Date(scheduledAt) <= /* @__PURE__ */ new Date()) {
|
|
1274
|
+
throw new utils.errors.ValidationError("Scheduled at must be later than now");
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
const createSchedulingService = ({ strapi: strapi2 }) => {
|
|
1279
|
+
const scheduledJobs = /* @__PURE__ */ new Map();
|
|
1280
|
+
return {
|
|
1281
|
+
async set(releaseId, scheduleDate) {
|
|
1282
|
+
const release2 = await strapi2.db.query(RELEASE_MODEL_UID).findOne({ where: { id: releaseId, releasedAt: null } });
|
|
1283
|
+
if (!release2) {
|
|
1284
|
+
throw new utils.errors.NotFoundError(`No release found for id ${releaseId}`);
|
|
1285
|
+
}
|
|
1286
|
+
const job = nodeSchedule.scheduleJob(scheduleDate, async () => {
|
|
1287
|
+
try {
|
|
1288
|
+
await getService("release", { strapi: strapi2 }).publish(releaseId);
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
}
|
|
1291
|
+
this.cancel(releaseId);
|
|
1292
|
+
});
|
|
1293
|
+
if (scheduledJobs.has(releaseId)) {
|
|
1294
|
+
this.cancel(releaseId);
|
|
1295
|
+
}
|
|
1296
|
+
scheduledJobs.set(releaseId, job);
|
|
1297
|
+
return scheduledJobs;
|
|
1298
|
+
},
|
|
1299
|
+
cancel(releaseId) {
|
|
1300
|
+
if (scheduledJobs.has(releaseId)) {
|
|
1301
|
+
scheduledJobs.get(releaseId).cancel();
|
|
1302
|
+
scheduledJobs.delete(releaseId);
|
|
1303
|
+
}
|
|
1304
|
+
return scheduledJobs;
|
|
1305
|
+
},
|
|
1306
|
+
getAll() {
|
|
1307
|
+
return scheduledJobs;
|
|
1308
|
+
},
|
|
1309
|
+
/**
|
|
1461
1310
|
* On bootstrap, we can use this function to make sure to sync the scheduled jobs from the database that are not yet released
|
|
1462
1311
|
* This is useful in case the server was restarted and the scheduled jobs were lost
|
|
1463
1312
|
* This also could be used to sync different Strapi instances in case of a cluster
|
|
1464
|
-
*/
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
});
|
|
1473
|
-
for (const release of releases){
|
|
1474
|
-
this.set(release.id, release.scheduledAt);
|
|
1475
|
-
}
|
|
1476
|
-
return scheduledJobs;
|
|
1313
|
+
*/
|
|
1314
|
+
async syncFromDatabase() {
|
|
1315
|
+
const releases = await strapi2.db.query(RELEASE_MODEL_UID).findMany({
|
|
1316
|
+
where: {
|
|
1317
|
+
scheduledAt: {
|
|
1318
|
+
$gte: /* @__PURE__ */ new Date()
|
|
1319
|
+
},
|
|
1320
|
+
releasedAt: null
|
|
1477
1321
|
}
|
|
1478
|
-
|
|
1322
|
+
});
|
|
1323
|
+
for (const release2 of releases) {
|
|
1324
|
+
this.set(release2.id, release2.scheduledAt);
|
|
1325
|
+
}
|
|
1326
|
+
return scheduledJobs;
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1479
1329
|
};
|
|
1480
|
-
|
|
1481
1330
|
const DEFAULT_SETTINGS = {
|
|
1482
|
-
|
|
1331
|
+
defaultTimezone: null
|
|
1483
1332
|
};
|
|
1484
|
-
const createSettingsService = ({ strapi })=>{
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
key: 'settings'
|
|
1502
|
-
});
|
|
1503
|
-
return {
|
|
1504
|
-
...DEFAULT_SETTINGS,
|
|
1505
|
-
...settings || {}
|
|
1506
|
-
};
|
|
1507
|
-
}
|
|
1508
|
-
};
|
|
1333
|
+
const createSettingsService = ({ strapi: strapi2 }) => {
|
|
1334
|
+
const getStore = async () => strapi2.store({ type: "core", name: "content-releases" });
|
|
1335
|
+
return {
|
|
1336
|
+
async update({ settings: settings2 }) {
|
|
1337
|
+
const store = await getStore();
|
|
1338
|
+
store.set({ key: "settings", value: settings2 });
|
|
1339
|
+
return settings2;
|
|
1340
|
+
},
|
|
1341
|
+
async find() {
|
|
1342
|
+
const store = await getStore();
|
|
1343
|
+
const settings2 = await store.get({ key: "settings" });
|
|
1344
|
+
return {
|
|
1345
|
+
...DEFAULT_SETTINGS,
|
|
1346
|
+
...settings2 || {}
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1509
1350
|
};
|
|
1510
|
-
|
|
1511
1351
|
const services = {
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1352
|
+
release: createReleaseService,
|
|
1353
|
+
"release-action": createReleaseActionService,
|
|
1354
|
+
"release-validation": createReleaseValidationService,
|
|
1355
|
+
scheduling: createSchedulingService,
|
|
1356
|
+
settings: createSettingsService
|
|
1517
1357
|
};
|
|
1518
|
-
|
|
1519
1358
|
const RELEASE_SCHEMA = utils.yup.object().shape({
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1359
|
+
name: utils.yup.string().trim().required(),
|
|
1360
|
+
scheduledAt: utils.yup.string().nullable(),
|
|
1361
|
+
timezone: utils.yup.string().when("scheduledAt", {
|
|
1362
|
+
is: (value) => value !== null && value !== void 0,
|
|
1363
|
+
then: utils.yup.string().required(),
|
|
1364
|
+
otherwise: utils.yup.string().nullable()
|
|
1365
|
+
})
|
|
1527
1366
|
}).required().noUnknown();
|
|
1528
1367
|
const FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA = utils.yup.object().shape({
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1368
|
+
contentType: utils.yup.string().required(),
|
|
1369
|
+
entryDocumentId: utils.yup.string().nullable(),
|
|
1370
|
+
hasEntryAttached: utils.yup.string().nullable(),
|
|
1371
|
+
locale: utils.yup.string().nullable()
|
|
1533
1372
|
}).required().noUnknown();
|
|
1534
1373
|
const validateRelease = utils.validateYupSchema(RELEASE_SCHEMA);
|
|
1535
|
-
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1536
|
-
|
|
1374
|
+
const validatefindByDocumentAttachedParams = utils.validateYupSchema(
|
|
1375
|
+
FIND_BY_DOCUMENT_ATTACHED_PARAMS_SCHEMA
|
|
1376
|
+
);
|
|
1537
1377
|
const releaseController = {
|
|
1538
|
-
|
|
1378
|
+
/**
|
|
1539
1379
|
* Find releases based on documents attached or not to the release.
|
|
1540
1380
|
* If `hasEntryAttached` is true, it will return all releases that have the entry attached.
|
|
1541
1381
|
* If `hasEntryAttached` is false, it will return all releases that don't have the entry attached.
|
|
1542
|
-
*/
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1382
|
+
*/
|
|
1383
|
+
async findByDocumentAttached(ctx) {
|
|
1384
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1385
|
+
ability: ctx.state.userAbility,
|
|
1386
|
+
model: RELEASE_MODEL_UID
|
|
1387
|
+
});
|
|
1388
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1389
|
+
const releaseService = getService("release", { strapi });
|
|
1390
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1391
|
+
await validatefindByDocumentAttachedParams(query);
|
|
1392
|
+
const model = strapi.getModel(query.contentType);
|
|
1393
|
+
if (model.kind && model.kind === "singleType") {
|
|
1394
|
+
const document = await strapi.db.query(model.uid).findOne({ select: ["documentId"] });
|
|
1395
|
+
if (!document) {
|
|
1396
|
+
throw new utils.errors.NotFoundError(`No entry found for contentType ${query.contentType}`);
|
|
1397
|
+
}
|
|
1398
|
+
query.entryDocumentId = document.documentId;
|
|
1399
|
+
}
|
|
1400
|
+
const { contentType, hasEntryAttached, entryDocumentId, locale } = query;
|
|
1401
|
+
const isEntryAttached = typeof hasEntryAttached === "string" ? Boolean(JSON.parse(hasEntryAttached)) : false;
|
|
1402
|
+
if (isEntryAttached) {
|
|
1403
|
+
const releases = await releaseService.findMany({
|
|
1404
|
+
where: {
|
|
1405
|
+
releasedAt: null,
|
|
1406
|
+
actions: {
|
|
1407
|
+
contentType,
|
|
1408
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1409
|
+
locale: locale ?? null
|
|
1410
|
+
}
|
|
1411
|
+
},
|
|
1412
|
+
populate: {
|
|
1413
|
+
actions: {
|
|
1414
|
+
fields: ["type"],
|
|
1415
|
+
filters: {
|
|
1416
|
+
contentType,
|
|
1417
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1418
|
+
locale: locale ?? null
|
|
1563
1419
|
}
|
|
1564
|
-
|
|
1420
|
+
}
|
|
1565
1421
|
}
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
},
|
|
1578
|
-
populate: {
|
|
1579
|
-
actions: {
|
|
1580
|
-
fields: [
|
|
1581
|
-
'type'
|
|
1582
|
-
],
|
|
1583
|
-
filters: {
|
|
1584
|
-
contentType,
|
|
1585
|
-
entryDocumentId: entryDocumentId ?? null,
|
|
1586
|
-
locale: locale ?? null
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
});
|
|
1591
|
-
ctx.body = {
|
|
1592
|
-
data: releases
|
|
1593
|
-
};
|
|
1594
|
-
} else {
|
|
1595
|
-
const relatedReleases = await releaseService.findMany({
|
|
1596
|
-
where: {
|
|
1597
|
-
releasedAt: null,
|
|
1598
|
-
actions: {
|
|
1599
|
-
contentType,
|
|
1600
|
-
entryDocumentId: entryDocumentId ?? null,
|
|
1601
|
-
locale: locale ?? null
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
});
|
|
1605
|
-
const releases = await releaseService.findMany({
|
|
1606
|
-
where: {
|
|
1607
|
-
$or: [
|
|
1608
|
-
{
|
|
1609
|
-
id: {
|
|
1610
|
-
$notIn: relatedReleases.map((release)=>release.id)
|
|
1611
|
-
}
|
|
1612
|
-
},
|
|
1613
|
-
{
|
|
1614
|
-
actions: null
|
|
1615
|
-
}
|
|
1616
|
-
],
|
|
1617
|
-
releasedAt: null
|
|
1618
|
-
}
|
|
1619
|
-
});
|
|
1620
|
-
ctx.body = {
|
|
1621
|
-
data: releases
|
|
1622
|
-
};
|
|
1422
|
+
});
|
|
1423
|
+
ctx.body = { data: releases };
|
|
1424
|
+
} else {
|
|
1425
|
+
const relatedReleases = await releaseService.findMany({
|
|
1426
|
+
where: {
|
|
1427
|
+
releasedAt: null,
|
|
1428
|
+
actions: {
|
|
1429
|
+
contentType,
|
|
1430
|
+
entryDocumentId: entryDocumentId ?? null,
|
|
1431
|
+
locale: locale ?? null
|
|
1432
|
+
}
|
|
1623
1433
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
const { results, pagination } = await releaseService.findPage(query);
|
|
1636
|
-
const data = results.map((release)=>{
|
|
1637
|
-
const { actions, ...releaseData } = release;
|
|
1638
|
-
return {
|
|
1639
|
-
...releaseData,
|
|
1640
|
-
actions: {
|
|
1641
|
-
meta: {
|
|
1642
|
-
count: actions.count
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
};
|
|
1646
|
-
});
|
|
1647
|
-
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1648
|
-
where: {
|
|
1649
|
-
releasedAt: null
|
|
1650
|
-
}
|
|
1651
|
-
});
|
|
1652
|
-
ctx.body = {
|
|
1653
|
-
data,
|
|
1654
|
-
meta: {
|
|
1655
|
-
pagination,
|
|
1656
|
-
pendingReleasesCount
|
|
1434
|
+
});
|
|
1435
|
+
const releases = await releaseService.findMany({
|
|
1436
|
+
where: {
|
|
1437
|
+
$or: [
|
|
1438
|
+
{
|
|
1439
|
+
id: {
|
|
1440
|
+
$notIn: relatedReleases.map((release2) => release2.id)
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
{
|
|
1444
|
+
actions: null
|
|
1657
1445
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
async findOne (ctx) {
|
|
1661
|
-
const id = ctx.params.id;
|
|
1662
|
-
const releaseService = getService('release', {
|
|
1663
|
-
strapi
|
|
1664
|
-
});
|
|
1665
|
-
const releaseActionService = getService('release-action', {
|
|
1666
|
-
strapi
|
|
1667
|
-
});
|
|
1668
|
-
const release = await releaseService.findOne(id, {
|
|
1669
|
-
populate: [
|
|
1670
|
-
'createdBy'
|
|
1671
|
-
]
|
|
1672
|
-
});
|
|
1673
|
-
if (!release) {
|
|
1674
|
-
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1446
|
+
],
|
|
1447
|
+
releasedAt: null
|
|
1675
1448
|
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
},
|
|
1698
|
-
async mapEntriesToReleases (ctx) {
|
|
1699
|
-
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1700
|
-
if (!contentTypeUid || !documentIds) {
|
|
1701
|
-
throw new utils.errors.ValidationError('Missing required query parameters');
|
|
1449
|
+
});
|
|
1450
|
+
ctx.body = { data: releases };
|
|
1451
|
+
}
|
|
1452
|
+
},
|
|
1453
|
+
async findPage(ctx) {
|
|
1454
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1455
|
+
ability: ctx.state.userAbility,
|
|
1456
|
+
model: RELEASE_MODEL_UID
|
|
1457
|
+
});
|
|
1458
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
1459
|
+
const releaseService = getService("release", { strapi });
|
|
1460
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1461
|
+
const { results, pagination } = await releaseService.findPage(query);
|
|
1462
|
+
const data = results.map((release2) => {
|
|
1463
|
+
const { actions, ...releaseData } = release2;
|
|
1464
|
+
return {
|
|
1465
|
+
...releaseData,
|
|
1466
|
+
actions: {
|
|
1467
|
+
meta: {
|
|
1468
|
+
count: actions.count
|
|
1469
|
+
}
|
|
1702
1470
|
}
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
return acc;
|
|
1744
|
-
}, {});
|
|
1745
|
-
ctx.body = {
|
|
1746
|
-
data: mappedEntriesInReleases
|
|
1747
|
-
};
|
|
1748
|
-
},
|
|
1749
|
-
async create (ctx) {
|
|
1750
|
-
const user = ctx.state.user;
|
|
1751
|
-
const releaseArgs = ctx.request.body;
|
|
1752
|
-
await validateRelease(releaseArgs);
|
|
1753
|
-
const releaseService = getService('release', {
|
|
1754
|
-
strapi
|
|
1755
|
-
});
|
|
1756
|
-
const release = await releaseService.create(releaseArgs, {
|
|
1757
|
-
user
|
|
1758
|
-
});
|
|
1759
|
-
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
|
1760
|
-
ability: ctx.state.userAbility,
|
|
1761
|
-
model: RELEASE_MODEL_UID
|
|
1762
|
-
});
|
|
1763
|
-
ctx.created({
|
|
1764
|
-
data: await permissionsManager.sanitizeOutput(release)
|
|
1765
|
-
});
|
|
1766
|
-
},
|
|
1767
|
-
async update (ctx) {
|
|
1768
|
-
const user = ctx.state.user;
|
|
1769
|
-
const releaseArgs = ctx.request.body;
|
|
1770
|
-
const id = ctx.params.id;
|
|
1771
|
-
await validateRelease(releaseArgs);
|
|
1772
|
-
const releaseService = getService('release', {
|
|
1773
|
-
strapi
|
|
1774
|
-
});
|
|
1775
|
-
const release = await releaseService.update(id, releaseArgs, {
|
|
1776
|
-
user
|
|
1777
|
-
});
|
|
1778
|
-
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
|
1779
|
-
ability: ctx.state.userAbility,
|
|
1780
|
-
model: RELEASE_MODEL_UID
|
|
1781
|
-
});
|
|
1782
|
-
ctx.body = {
|
|
1783
|
-
data: await permissionsManager.sanitizeOutput(release)
|
|
1784
|
-
};
|
|
1785
|
-
},
|
|
1786
|
-
async delete (ctx) {
|
|
1787
|
-
const id = ctx.params.id;
|
|
1788
|
-
const releaseService = getService('release', {
|
|
1789
|
-
strapi
|
|
1790
|
-
});
|
|
1791
|
-
const release = await releaseService.delete(id);
|
|
1792
|
-
ctx.body = {
|
|
1793
|
-
data: release
|
|
1794
|
-
};
|
|
1795
|
-
},
|
|
1796
|
-
async publish (ctx) {
|
|
1797
|
-
const id = ctx.params.id;
|
|
1798
|
-
const releaseService = getService('release', {
|
|
1799
|
-
strapi
|
|
1800
|
-
});
|
|
1801
|
-
const releaseActionService = getService('release-action', {
|
|
1802
|
-
strapi
|
|
1803
|
-
});
|
|
1804
|
-
const release = await releaseService.publish(id);
|
|
1805
|
-
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1806
|
-
releaseActionService.countActions({
|
|
1807
|
-
filters: {
|
|
1808
|
-
release: id,
|
|
1809
|
-
type: 'publish'
|
|
1810
|
-
}
|
|
1811
|
-
}),
|
|
1812
|
-
releaseActionService.countActions({
|
|
1813
|
-
filters: {
|
|
1814
|
-
release: id,
|
|
1815
|
-
type: 'unpublish'
|
|
1816
|
-
}
|
|
1817
|
-
})
|
|
1818
|
-
]);
|
|
1819
|
-
ctx.body = {
|
|
1820
|
-
data: release,
|
|
1821
|
-
meta: {
|
|
1822
|
-
totalEntries: countPublishActions + countUnpublishActions,
|
|
1823
|
-
totalPublishedEntries: countPublishActions,
|
|
1824
|
-
totalUnpublishedEntries: countUnpublishActions
|
|
1825
|
-
}
|
|
1826
|
-
};
|
|
1471
|
+
};
|
|
1472
|
+
});
|
|
1473
|
+
const pendingReleasesCount = await strapi.db.query(RELEASE_MODEL_UID).count({
|
|
1474
|
+
where: {
|
|
1475
|
+
releasedAt: null
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
ctx.body = { data, meta: { pagination, pendingReleasesCount } };
|
|
1479
|
+
},
|
|
1480
|
+
async findOne(ctx) {
|
|
1481
|
+
const id = ctx.params.id;
|
|
1482
|
+
const releaseService = getService("release", { strapi });
|
|
1483
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1484
|
+
const release2 = await releaseService.findOne(id, { populate: ["createdBy"] });
|
|
1485
|
+
if (!release2) {
|
|
1486
|
+
throw new utils.errors.NotFoundError(`Release not found for id: ${id}`);
|
|
1487
|
+
}
|
|
1488
|
+
const count = await releaseActionService.countActions({
|
|
1489
|
+
filters: {
|
|
1490
|
+
release: id
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
const sanitizedRelease = {
|
|
1494
|
+
...release2,
|
|
1495
|
+
createdBy: release2.createdBy ? strapi.service("admin::user").sanitizeUser(release2.createdBy) : null
|
|
1496
|
+
};
|
|
1497
|
+
const data = {
|
|
1498
|
+
...sanitizedRelease,
|
|
1499
|
+
actions: {
|
|
1500
|
+
meta: {
|
|
1501
|
+
count
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
ctx.body = { data };
|
|
1506
|
+
},
|
|
1507
|
+
async mapEntriesToReleases(ctx) {
|
|
1508
|
+
const { contentTypeUid, documentIds, locale } = ctx.query;
|
|
1509
|
+
if (!contentTypeUid || !documentIds) {
|
|
1510
|
+
throw new utils.errors.ValidationError("Missing required query parameters");
|
|
1827
1511
|
}
|
|
1512
|
+
const releaseService = getService("release", { strapi });
|
|
1513
|
+
const releasesWithActions = await releaseService.findMany({
|
|
1514
|
+
where: {
|
|
1515
|
+
releasedAt: null,
|
|
1516
|
+
actions: {
|
|
1517
|
+
contentType: contentTypeUid,
|
|
1518
|
+
entryDocumentId: {
|
|
1519
|
+
$in: documentIds
|
|
1520
|
+
},
|
|
1521
|
+
locale
|
|
1522
|
+
}
|
|
1523
|
+
},
|
|
1524
|
+
populate: {
|
|
1525
|
+
actions: true
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
const mappedEntriesInReleases = releasesWithActions.reduce(
|
|
1529
|
+
(acc, release2) => {
|
|
1530
|
+
release2.actions.forEach((action) => {
|
|
1531
|
+
if (action.contentType !== contentTypeUid) {
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
if (locale && action.locale !== locale) {
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
if (!acc[action.entryDocumentId]) {
|
|
1538
|
+
acc[action.entryDocumentId] = [{ id: release2.id, name: release2.name }];
|
|
1539
|
+
} else {
|
|
1540
|
+
acc[action.entryDocumentId].push({ id: release2.id, name: release2.name });
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
return acc;
|
|
1544
|
+
},
|
|
1545
|
+
{}
|
|
1546
|
+
);
|
|
1547
|
+
ctx.body = {
|
|
1548
|
+
data: mappedEntriesInReleases
|
|
1549
|
+
};
|
|
1550
|
+
},
|
|
1551
|
+
async create(ctx) {
|
|
1552
|
+
const user = ctx.state.user;
|
|
1553
|
+
const releaseArgs = ctx.request.body;
|
|
1554
|
+
await validateRelease(releaseArgs);
|
|
1555
|
+
const releaseService = getService("release", { strapi });
|
|
1556
|
+
const release2 = await releaseService.create(releaseArgs, { user });
|
|
1557
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1558
|
+
ability: ctx.state.userAbility,
|
|
1559
|
+
model: RELEASE_MODEL_UID
|
|
1560
|
+
});
|
|
1561
|
+
ctx.created({
|
|
1562
|
+
data: await permissionsManager.sanitizeOutput(release2)
|
|
1563
|
+
});
|
|
1564
|
+
},
|
|
1565
|
+
async update(ctx) {
|
|
1566
|
+
const user = ctx.state.user;
|
|
1567
|
+
const releaseArgs = ctx.request.body;
|
|
1568
|
+
const id = ctx.params.id;
|
|
1569
|
+
await validateRelease(releaseArgs);
|
|
1570
|
+
const releaseService = getService("release", { strapi });
|
|
1571
|
+
const release2 = await releaseService.update(id, releaseArgs, { user });
|
|
1572
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1573
|
+
ability: ctx.state.userAbility,
|
|
1574
|
+
model: RELEASE_MODEL_UID
|
|
1575
|
+
});
|
|
1576
|
+
ctx.body = {
|
|
1577
|
+
data: await permissionsManager.sanitizeOutput(release2)
|
|
1578
|
+
};
|
|
1579
|
+
},
|
|
1580
|
+
async delete(ctx) {
|
|
1581
|
+
const id = ctx.params.id;
|
|
1582
|
+
const releaseService = getService("release", { strapi });
|
|
1583
|
+
const release2 = await releaseService.delete(id);
|
|
1584
|
+
ctx.body = {
|
|
1585
|
+
data: release2
|
|
1586
|
+
};
|
|
1587
|
+
},
|
|
1588
|
+
async publish(ctx) {
|
|
1589
|
+
const id = ctx.params.id;
|
|
1590
|
+
const releaseService = getService("release", { strapi });
|
|
1591
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1592
|
+
const release2 = await releaseService.publish(id);
|
|
1593
|
+
const [countPublishActions, countUnpublishActions] = await Promise.all([
|
|
1594
|
+
releaseActionService.countActions({
|
|
1595
|
+
filters: {
|
|
1596
|
+
release: id,
|
|
1597
|
+
type: "publish"
|
|
1598
|
+
}
|
|
1599
|
+
}),
|
|
1600
|
+
releaseActionService.countActions({
|
|
1601
|
+
filters: {
|
|
1602
|
+
release: id,
|
|
1603
|
+
type: "unpublish"
|
|
1604
|
+
}
|
|
1605
|
+
})
|
|
1606
|
+
]);
|
|
1607
|
+
ctx.body = {
|
|
1608
|
+
data: release2,
|
|
1609
|
+
meta: {
|
|
1610
|
+
totalEntries: countPublishActions + countUnpublishActions,
|
|
1611
|
+
totalPublishedEntries: countPublishActions,
|
|
1612
|
+
totalUnpublishedEntries: countUnpublishActions
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1828
1616
|
};
|
|
1829
|
-
|
|
1830
1617
|
const RELEASE_ACTION_SCHEMA = utils.yup.object().shape({
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
'publish',
|
|
1836
|
-
'unpublish'
|
|
1837
|
-
]).required()
|
|
1618
|
+
contentType: utils.yup.string().required(),
|
|
1619
|
+
entryDocumentId: utils.yup.strapiID(),
|
|
1620
|
+
locale: utils.yup.string(),
|
|
1621
|
+
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1838
1622
|
});
|
|
1839
1623
|
const RELEASE_ACTION_UPDATE_SCHEMA = utils.yup.object().shape({
|
|
1840
|
-
|
|
1841
|
-
'publish',
|
|
1842
|
-
'unpublish'
|
|
1843
|
-
]).required()
|
|
1624
|
+
type: utils.yup.string().oneOf(["publish", "unpublish"]).required()
|
|
1844
1625
|
});
|
|
1845
1626
|
const FIND_MANY_ACTIONS_PARAMS = utils.yup.object().shape({
|
|
1846
|
-
|
|
1847
|
-
'action',
|
|
1848
|
-
'contentType',
|
|
1849
|
-
'locale'
|
|
1850
|
-
])
|
|
1627
|
+
groupBy: utils.yup.string().oneOf(["action", "contentType", "locale"])
|
|
1851
1628
|
});
|
|
1852
1629
|
const validateReleaseAction = utils.validateYupSchema(RELEASE_ACTION_SCHEMA);
|
|
1853
1630
|
const validateReleaseActionUpdateSchema = utils.validateYupSchema(RELEASE_ACTION_UPDATE_SCHEMA);
|
|
1854
1631
|
const validateFindManyActionsParams = utils.validateYupSchema(FIND_MANY_ACTIONS_PARAMS);
|
|
1855
|
-
|
|
1856
1632
|
const releaseActionController = {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
try {
|
|
1882
|
-
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1883
|
-
disableUpdateReleaseStatus: true
|
|
1884
|
-
});
|
|
1885
|
-
return action;
|
|
1886
|
-
} catch (error) {
|
|
1887
|
-
// If the entry is already in the release, we don't want to throw an error, so we catch and ignore it
|
|
1888
|
-
if (error instanceof AlreadyOnReleaseError) {
|
|
1889
|
-
return null;
|
|
1890
|
-
}
|
|
1891
|
-
throw error;
|
|
1892
|
-
}
|
|
1893
|
-
}));
|
|
1894
|
-
return releaseActions;
|
|
1895
|
-
});
|
|
1896
|
-
const newReleaseActions = releaseActions.filter((action)=>action !== null);
|
|
1897
|
-
if (newReleaseActions.length > 0) {
|
|
1898
|
-
releaseService.updateReleaseStatus(releaseId);
|
|
1899
|
-
}
|
|
1900
|
-
ctx.created({
|
|
1901
|
-
data: newReleaseActions,
|
|
1902
|
-
meta: {
|
|
1903
|
-
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1904
|
-
totalEntries: releaseActions.length
|
|
1905
|
-
}
|
|
1906
|
-
});
|
|
1907
|
-
},
|
|
1908
|
-
async findMany (ctx) {
|
|
1909
|
-
const releaseId = ctx.params.releaseId;
|
|
1910
|
-
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
|
1911
|
-
ability: ctx.state.userAbility,
|
|
1912
|
-
model: RELEASE_ACTION_MODEL_UID
|
|
1913
|
-
});
|
|
1914
|
-
await validateFindManyActionsParams(ctx.query);
|
|
1915
|
-
if (ctx.query.groupBy) {
|
|
1916
|
-
if (![
|
|
1917
|
-
'action',
|
|
1918
|
-
'contentType',
|
|
1919
|
-
'locale'
|
|
1920
|
-
].includes(ctx.query.groupBy)) {
|
|
1921
|
-
ctx.badRequest('Invalid groupBy parameter');
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
|
-
ctx.query.sort = ctx.query.groupBy === 'action' ? 'type' : ctx.query.groupBy;
|
|
1925
|
-
delete ctx.query.groupBy;
|
|
1926
|
-
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1927
|
-
const releaseActionService = getService('release-action', {
|
|
1928
|
-
strapi
|
|
1929
|
-
});
|
|
1930
|
-
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1931
|
-
...query
|
|
1932
|
-
});
|
|
1933
|
-
/**
|
|
1934
|
-
* Release actions can be related to entries of different content types.
|
|
1935
|
-
* We need to sanitize the entry output according to that content type.
|
|
1936
|
-
* So, we group the sanitized output function by content type.
|
|
1937
|
-
*/ const contentTypeOutputSanitizers = results.reduce((acc, action)=>{
|
|
1938
|
-
if (acc[action.contentType]) {
|
|
1939
|
-
return acc;
|
|
1940
|
-
}
|
|
1941
|
-
const contentTypePermissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
|
1942
|
-
ability: ctx.state.userAbility,
|
|
1943
|
-
model: action.contentType
|
|
1633
|
+
async create(ctx) {
|
|
1634
|
+
const releaseId = ctx.params.releaseId;
|
|
1635
|
+
const releaseActionArgs = ctx.request.body;
|
|
1636
|
+
await validateReleaseAction(releaseActionArgs);
|
|
1637
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1638
|
+
const releaseAction2 = await releaseActionService.create(releaseId, releaseActionArgs);
|
|
1639
|
+
ctx.created({
|
|
1640
|
+
data: releaseAction2
|
|
1641
|
+
});
|
|
1642
|
+
},
|
|
1643
|
+
async createMany(ctx) {
|
|
1644
|
+
const releaseId = ctx.params.releaseId;
|
|
1645
|
+
const releaseActionsArgs = ctx.request.body;
|
|
1646
|
+
await Promise.all(
|
|
1647
|
+
releaseActionsArgs.map((releaseActionArgs) => validateReleaseAction(releaseActionArgs))
|
|
1648
|
+
);
|
|
1649
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1650
|
+
const releaseService = getService("release", { strapi });
|
|
1651
|
+
const releaseActions = await strapi.db.transaction(async () => {
|
|
1652
|
+
const releaseActions2 = await Promise.all(
|
|
1653
|
+
releaseActionsArgs.map(async (releaseActionArgs) => {
|
|
1654
|
+
try {
|
|
1655
|
+
const action = await releaseActionService.create(releaseId, releaseActionArgs, {
|
|
1656
|
+
disableUpdateReleaseStatus: true
|
|
1944
1657
|
});
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
ctx.body = {
|
|
1980
|
-
data: updatedAction
|
|
1981
|
-
};
|
|
1982
|
-
},
|
|
1983
|
-
async delete (ctx) {
|
|
1984
|
-
const actionId = ctx.params.actionId;
|
|
1985
|
-
const releaseId = ctx.params.releaseId;
|
|
1986
|
-
const releaseActionService = getService('release-action', {
|
|
1987
|
-
strapi
|
|
1988
|
-
});
|
|
1989
|
-
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1990
|
-
ctx.body = {
|
|
1991
|
-
data: deletedReleaseAction
|
|
1992
|
-
};
|
|
1658
|
+
return action;
|
|
1659
|
+
} catch (error) {
|
|
1660
|
+
if (error instanceof AlreadyOnReleaseError) {
|
|
1661
|
+
return null;
|
|
1662
|
+
}
|
|
1663
|
+
throw error;
|
|
1664
|
+
}
|
|
1665
|
+
})
|
|
1666
|
+
);
|
|
1667
|
+
return releaseActions2;
|
|
1668
|
+
});
|
|
1669
|
+
const newReleaseActions = releaseActions.filter((action) => action !== null);
|
|
1670
|
+
if (newReleaseActions.length > 0) {
|
|
1671
|
+
releaseService.updateReleaseStatus(releaseId);
|
|
1672
|
+
}
|
|
1673
|
+
ctx.created({
|
|
1674
|
+
data: newReleaseActions,
|
|
1675
|
+
meta: {
|
|
1676
|
+
entriesAlreadyInRelease: releaseActions.length - newReleaseActions.length,
|
|
1677
|
+
totalEntries: releaseActions.length
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
},
|
|
1681
|
+
async findMany(ctx) {
|
|
1682
|
+
const releaseId = ctx.params.releaseId;
|
|
1683
|
+
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1684
|
+
ability: ctx.state.userAbility,
|
|
1685
|
+
model: RELEASE_ACTION_MODEL_UID
|
|
1686
|
+
});
|
|
1687
|
+
await validateFindManyActionsParams(ctx.query);
|
|
1688
|
+
if (ctx.query.groupBy) {
|
|
1689
|
+
if (!["action", "contentType", "locale"].includes(ctx.query.groupBy)) {
|
|
1690
|
+
ctx.badRequest("Invalid groupBy parameter");
|
|
1691
|
+
}
|
|
1993
1692
|
}
|
|
1693
|
+
ctx.query.sort = ctx.query.groupBy === "action" ? "type" : ctx.query.groupBy;
|
|
1694
|
+
delete ctx.query.groupBy;
|
|
1695
|
+
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
1696
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1697
|
+
const { results, pagination } = await releaseActionService.findPage(releaseId, {
|
|
1698
|
+
...query
|
|
1699
|
+
});
|
|
1700
|
+
const contentTypeOutputSanitizers = results.reduce((acc, action) => {
|
|
1701
|
+
if (acc[action.contentType]) {
|
|
1702
|
+
return acc;
|
|
1703
|
+
}
|
|
1704
|
+
const contentTypePermissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
1705
|
+
ability: ctx.state.userAbility,
|
|
1706
|
+
model: action.contentType
|
|
1707
|
+
});
|
|
1708
|
+
acc[action.contentType] = contentTypePermissionsManager.sanitizeOutput;
|
|
1709
|
+
return acc;
|
|
1710
|
+
}, {});
|
|
1711
|
+
const sanitizedResults = await utils.async.map(results, async (action) => ({
|
|
1712
|
+
...action,
|
|
1713
|
+
entry: action.entry ? await contentTypeOutputSanitizers[action.contentType](action.entry) : {}
|
|
1714
|
+
}));
|
|
1715
|
+
const groupedData = await releaseActionService.groupActions(sanitizedResults, query.sort);
|
|
1716
|
+
const contentTypes2 = await releaseActionService.getContentTypeModelsFromActions(results);
|
|
1717
|
+
const releaseService = getService("release", { strapi });
|
|
1718
|
+
const components = await releaseService.getAllComponents();
|
|
1719
|
+
ctx.body = {
|
|
1720
|
+
data: groupedData,
|
|
1721
|
+
meta: {
|
|
1722
|
+
pagination,
|
|
1723
|
+
contentTypes: contentTypes2,
|
|
1724
|
+
components
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
},
|
|
1728
|
+
async update(ctx) {
|
|
1729
|
+
const actionId = ctx.params.actionId;
|
|
1730
|
+
const releaseId = ctx.params.releaseId;
|
|
1731
|
+
const releaseActionUpdateArgs = ctx.request.body;
|
|
1732
|
+
await validateReleaseActionUpdateSchema(releaseActionUpdateArgs);
|
|
1733
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1734
|
+
const updatedAction = await releaseActionService.update(
|
|
1735
|
+
actionId,
|
|
1736
|
+
releaseId,
|
|
1737
|
+
releaseActionUpdateArgs
|
|
1738
|
+
);
|
|
1739
|
+
ctx.body = {
|
|
1740
|
+
data: updatedAction
|
|
1741
|
+
};
|
|
1742
|
+
},
|
|
1743
|
+
async delete(ctx) {
|
|
1744
|
+
const actionId = ctx.params.actionId;
|
|
1745
|
+
const releaseId = ctx.params.releaseId;
|
|
1746
|
+
const releaseActionService = getService("release-action", { strapi });
|
|
1747
|
+
const deletedReleaseAction = await releaseActionService.delete(actionId, releaseId);
|
|
1748
|
+
ctx.body = {
|
|
1749
|
+
data: deletedReleaseAction
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1994
1752
|
};
|
|
1995
|
-
|
|
1996
1753
|
const SETTINGS_SCHEMA = yup__namespace.object().shape({
|
|
1997
|
-
|
|
1754
|
+
defaultTimezone: yup__namespace.string().nullable().default(null)
|
|
1998
1755
|
}).required().noUnknown();
|
|
1999
1756
|
const validateSettings = utils.validateYupSchema(SETTINGS_SCHEMA);
|
|
2000
|
-
|
|
2001
1757
|
const settingsController = {
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
// Data validation
|
|
2015
|
-
const settingsBody = ctx.request.body;
|
|
2016
|
-
const settings = await validateSettings(settingsBody);
|
|
2017
|
-
// Update
|
|
2018
|
-
const settingsService = getService('settings', {
|
|
2019
|
-
strapi
|
|
2020
|
-
});
|
|
2021
|
-
const updatedSettings = await settingsService.update({
|
|
2022
|
-
settings
|
|
2023
|
-
});
|
|
2024
|
-
// Response
|
|
2025
|
-
ctx.body = {
|
|
2026
|
-
data: updatedSettings
|
|
2027
|
-
};
|
|
2028
|
-
}
|
|
1758
|
+
async find(ctx) {
|
|
1759
|
+
const settingsService = getService("settings", { strapi });
|
|
1760
|
+
const settings2 = await settingsService.find();
|
|
1761
|
+
ctx.body = { data: settings2 };
|
|
1762
|
+
},
|
|
1763
|
+
async update(ctx) {
|
|
1764
|
+
const settingsBody = ctx.request.body;
|
|
1765
|
+
const settings2 = await validateSettings(settingsBody);
|
|
1766
|
+
const settingsService = getService("settings", { strapi });
|
|
1767
|
+
const updatedSettings = await settingsService.update({ settings: settings2 });
|
|
1768
|
+
ctx.body = { data: updatedSettings };
|
|
1769
|
+
}
|
|
2029
1770
|
};
|
|
2030
|
-
|
|
2031
1771
|
const controllers = {
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
1772
|
+
release: releaseController,
|
|
1773
|
+
"release-action": releaseActionController,
|
|
1774
|
+
settings: settingsController
|
|
2035
1775
|
};
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
1776
|
+
const release = {
|
|
1777
|
+
type: "admin",
|
|
1778
|
+
routes: [
|
|
1779
|
+
{
|
|
1780
|
+
method: "GET",
|
|
1781
|
+
path: "/mapEntriesToReleases",
|
|
1782
|
+
handler: "release.mapEntriesToReleases",
|
|
1783
|
+
config: {
|
|
1784
|
+
policies: [
|
|
1785
|
+
"admin::isAuthenticatedAdmin",
|
|
1786
|
+
{
|
|
1787
|
+
name: "admin::hasPermissions",
|
|
2044
1788
|
config: {
|
|
2045
|
-
|
|
2046
|
-
'admin::isAuthenticatedAdmin',
|
|
2047
|
-
{
|
|
2048
|
-
name: 'admin::hasPermissions',
|
|
2049
|
-
config: {
|
|
2050
|
-
actions: [
|
|
2051
|
-
'plugin::content-releases.read'
|
|
2052
|
-
]
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
]
|
|
1789
|
+
actions: ["plugin::content-releases.read"]
|
|
2056
1790
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
1791
|
+
}
|
|
1792
|
+
]
|
|
1793
|
+
}
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
method: "GET",
|
|
1797
|
+
path: "/getByDocumentAttached",
|
|
1798
|
+
handler: "release.findByDocumentAttached",
|
|
1799
|
+
config: {
|
|
1800
|
+
policies: [
|
|
1801
|
+
"admin::isAuthenticatedAdmin",
|
|
1802
|
+
{
|
|
1803
|
+
name: "admin::hasPermissions",
|
|
2062
1804
|
config: {
|
|
2063
|
-
|
|
2064
|
-
'admin::isAuthenticatedAdmin',
|
|
2065
|
-
{
|
|
2066
|
-
name: 'admin::hasPermissions',
|
|
2067
|
-
config: {
|
|
2068
|
-
actions: [
|
|
2069
|
-
'plugin::content-releases.read'
|
|
2070
|
-
]
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
]
|
|
1805
|
+
actions: ["plugin::content-releases.read"]
|
|
2074
1806
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
1807
|
+
}
|
|
1808
|
+
]
|
|
1809
|
+
}
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
method: "POST",
|
|
1813
|
+
path: "/",
|
|
1814
|
+
handler: "release.create",
|
|
1815
|
+
config: {
|
|
1816
|
+
policies: [
|
|
1817
|
+
"admin::isAuthenticatedAdmin",
|
|
1818
|
+
{
|
|
1819
|
+
name: "admin::hasPermissions",
|
|
2080
1820
|
config: {
|
|
2081
|
-
|
|
2082
|
-
'admin::isAuthenticatedAdmin',
|
|
2083
|
-
{
|
|
2084
|
-
name: 'admin::hasPermissions',
|
|
2085
|
-
config: {
|
|
2086
|
-
actions: [
|
|
2087
|
-
'plugin::content-releases.create'
|
|
2088
|
-
]
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
]
|
|
1821
|
+
actions: ["plugin::content-releases.create"]
|
|
2092
1822
|
}
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
1823
|
+
}
|
|
1824
|
+
]
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
method: "GET",
|
|
1829
|
+
path: "/",
|
|
1830
|
+
handler: "release.findPage",
|
|
1831
|
+
config: {
|
|
1832
|
+
policies: [
|
|
1833
|
+
"admin::isAuthenticatedAdmin",
|
|
1834
|
+
{
|
|
1835
|
+
name: "admin::hasPermissions",
|
|
2098
1836
|
config: {
|
|
2099
|
-
|
|
2100
|
-
'admin::isAuthenticatedAdmin',
|
|
2101
|
-
{
|
|
2102
|
-
name: 'admin::hasPermissions',
|
|
2103
|
-
config: {
|
|
2104
|
-
actions: [
|
|
2105
|
-
'plugin::content-releases.read'
|
|
2106
|
-
]
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
]
|
|
1837
|
+
actions: ["plugin::content-releases.read"]
|
|
2110
1838
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
1839
|
+
}
|
|
1840
|
+
]
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
method: "GET",
|
|
1845
|
+
path: "/:id",
|
|
1846
|
+
handler: "release.findOne",
|
|
1847
|
+
config: {
|
|
1848
|
+
policies: [
|
|
1849
|
+
"admin::isAuthenticatedAdmin",
|
|
1850
|
+
{
|
|
1851
|
+
name: "admin::hasPermissions",
|
|
2116
1852
|
config: {
|
|
2117
|
-
|
|
2118
|
-
'admin::isAuthenticatedAdmin',
|
|
2119
|
-
{
|
|
2120
|
-
name: 'admin::hasPermissions',
|
|
2121
|
-
config: {
|
|
2122
|
-
actions: [
|
|
2123
|
-
'plugin::content-releases.read'
|
|
2124
|
-
]
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
]
|
|
1853
|
+
actions: ["plugin::content-releases.read"]
|
|
2128
1854
|
}
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
1855
|
+
}
|
|
1856
|
+
]
|
|
1857
|
+
}
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
method: "PUT",
|
|
1861
|
+
path: "/:id",
|
|
1862
|
+
handler: "release.update",
|
|
1863
|
+
config: {
|
|
1864
|
+
policies: [
|
|
1865
|
+
"admin::isAuthenticatedAdmin",
|
|
1866
|
+
{
|
|
1867
|
+
name: "admin::hasPermissions",
|
|
2134
1868
|
config: {
|
|
2135
|
-
|
|
2136
|
-
'admin::isAuthenticatedAdmin',
|
|
2137
|
-
{
|
|
2138
|
-
name: 'admin::hasPermissions',
|
|
2139
|
-
config: {
|
|
2140
|
-
actions: [
|
|
2141
|
-
'plugin::content-releases.update'
|
|
2142
|
-
]
|
|
2143
|
-
}
|
|
2144
|
-
}
|
|
2145
|
-
]
|
|
1869
|
+
actions: ["plugin::content-releases.update"]
|
|
2146
1870
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
1871
|
+
}
|
|
1872
|
+
]
|
|
1873
|
+
}
|
|
1874
|
+
},
|
|
1875
|
+
{
|
|
1876
|
+
method: "DELETE",
|
|
1877
|
+
path: "/:id",
|
|
1878
|
+
handler: "release.delete",
|
|
1879
|
+
config: {
|
|
1880
|
+
policies: [
|
|
1881
|
+
"admin::isAuthenticatedAdmin",
|
|
1882
|
+
{
|
|
1883
|
+
name: "admin::hasPermissions",
|
|
2152
1884
|
config: {
|
|
2153
|
-
|
|
2154
|
-
'admin::isAuthenticatedAdmin',
|
|
2155
|
-
{
|
|
2156
|
-
name: 'admin::hasPermissions',
|
|
2157
|
-
config: {
|
|
2158
|
-
actions: [
|
|
2159
|
-
'plugin::content-releases.delete'
|
|
2160
|
-
]
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
]
|
|
1885
|
+
actions: ["plugin::content-releases.delete"]
|
|
2164
1886
|
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
1887
|
+
}
|
|
1888
|
+
]
|
|
1889
|
+
}
|
|
1890
|
+
},
|
|
1891
|
+
{
|
|
1892
|
+
method: "POST",
|
|
1893
|
+
path: "/:id/publish",
|
|
1894
|
+
handler: "release.publish",
|
|
1895
|
+
config: {
|
|
1896
|
+
policies: [
|
|
1897
|
+
"admin::isAuthenticatedAdmin",
|
|
1898
|
+
{
|
|
1899
|
+
name: "admin::hasPermissions",
|
|
2170
1900
|
config: {
|
|
2171
|
-
|
|
2172
|
-
'admin::isAuthenticatedAdmin',
|
|
2173
|
-
{
|
|
2174
|
-
name: 'admin::hasPermissions',
|
|
2175
|
-
config: {
|
|
2176
|
-
actions: [
|
|
2177
|
-
'plugin::content-releases.publish'
|
|
2178
|
-
]
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
]
|
|
1901
|
+
actions: ["plugin::content-releases.publish"]
|
|
2182
1902
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
1903
|
+
}
|
|
1904
|
+
]
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
]
|
|
2185
1908
|
};
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
1909
|
+
const releaseAction = {
|
|
1910
|
+
type: "admin",
|
|
1911
|
+
routes: [
|
|
1912
|
+
{
|
|
1913
|
+
method: "POST",
|
|
1914
|
+
path: "/:releaseId/actions",
|
|
1915
|
+
handler: "release-action.create",
|
|
1916
|
+
config: {
|
|
1917
|
+
policies: [
|
|
1918
|
+
"admin::isAuthenticatedAdmin",
|
|
1919
|
+
{
|
|
1920
|
+
name: "admin::hasPermissions",
|
|
2194
1921
|
config: {
|
|
2195
|
-
|
|
2196
|
-
'admin::isAuthenticatedAdmin',
|
|
2197
|
-
{
|
|
2198
|
-
name: 'admin::hasPermissions',
|
|
2199
|
-
config: {
|
|
2200
|
-
actions: [
|
|
2201
|
-
'plugin::content-releases.create-action'
|
|
2202
|
-
]
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
]
|
|
1922
|
+
actions: ["plugin::content-releases.create-action"]
|
|
2206
1923
|
}
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
1924
|
+
}
|
|
1925
|
+
]
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
{
|
|
1929
|
+
method: "POST",
|
|
1930
|
+
path: "/:releaseId/actions/bulk",
|
|
1931
|
+
handler: "release-action.createMany",
|
|
1932
|
+
config: {
|
|
1933
|
+
policies: [
|
|
1934
|
+
"admin::isAuthenticatedAdmin",
|
|
1935
|
+
{
|
|
1936
|
+
name: "admin::hasPermissions",
|
|
2212
1937
|
config: {
|
|
2213
|
-
|
|
2214
|
-
'admin::isAuthenticatedAdmin',
|
|
2215
|
-
{
|
|
2216
|
-
name: 'admin::hasPermissions',
|
|
2217
|
-
config: {
|
|
2218
|
-
actions: [
|
|
2219
|
-
'plugin::content-releases.create-action'
|
|
2220
|
-
]
|
|
2221
|
-
}
|
|
2222
|
-
}
|
|
2223
|
-
]
|
|
1938
|
+
actions: ["plugin::content-releases.create-action"]
|
|
2224
1939
|
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
1940
|
+
}
|
|
1941
|
+
]
|
|
1942
|
+
}
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
method: "GET",
|
|
1946
|
+
path: "/:releaseId/actions",
|
|
1947
|
+
handler: "release-action.findMany",
|
|
1948
|
+
config: {
|
|
1949
|
+
policies: [
|
|
1950
|
+
"admin::isAuthenticatedAdmin",
|
|
1951
|
+
{
|
|
1952
|
+
name: "admin::hasPermissions",
|
|
2230
1953
|
config: {
|
|
2231
|
-
|
|
2232
|
-
'admin::isAuthenticatedAdmin',
|
|
2233
|
-
{
|
|
2234
|
-
name: 'admin::hasPermissions',
|
|
2235
|
-
config: {
|
|
2236
|
-
actions: [
|
|
2237
|
-
'plugin::content-releases.read'
|
|
2238
|
-
]
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
]
|
|
1954
|
+
actions: ["plugin::content-releases.read"]
|
|
2242
1955
|
}
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
1956
|
+
}
|
|
1957
|
+
]
|
|
1958
|
+
}
|
|
1959
|
+
},
|
|
1960
|
+
{
|
|
1961
|
+
method: "PUT",
|
|
1962
|
+
path: "/:releaseId/actions/:actionId",
|
|
1963
|
+
handler: "release-action.update",
|
|
1964
|
+
config: {
|
|
1965
|
+
policies: [
|
|
1966
|
+
"admin::isAuthenticatedAdmin",
|
|
1967
|
+
{
|
|
1968
|
+
name: "admin::hasPermissions",
|
|
2248
1969
|
config: {
|
|
2249
|
-
|
|
2250
|
-
'admin::isAuthenticatedAdmin',
|
|
2251
|
-
{
|
|
2252
|
-
name: 'admin::hasPermissions',
|
|
2253
|
-
config: {
|
|
2254
|
-
actions: [
|
|
2255
|
-
'plugin::content-releases.update'
|
|
2256
|
-
]
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
]
|
|
1970
|
+
actions: ["plugin::content-releases.update"]
|
|
2260
1971
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
1972
|
+
}
|
|
1973
|
+
]
|
|
1974
|
+
}
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
method: "DELETE",
|
|
1978
|
+
path: "/:releaseId/actions/:actionId",
|
|
1979
|
+
handler: "release-action.delete",
|
|
1980
|
+
config: {
|
|
1981
|
+
policies: [
|
|
1982
|
+
"admin::isAuthenticatedAdmin",
|
|
1983
|
+
{
|
|
1984
|
+
name: "admin::hasPermissions",
|
|
2266
1985
|
config: {
|
|
2267
|
-
|
|
2268
|
-
'admin::isAuthenticatedAdmin',
|
|
2269
|
-
{
|
|
2270
|
-
name: 'admin::hasPermissions',
|
|
2271
|
-
config: {
|
|
2272
|
-
actions: [
|
|
2273
|
-
'plugin::content-releases.delete-action'
|
|
2274
|
-
]
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
]
|
|
1986
|
+
actions: ["plugin::content-releases.delete-action"]
|
|
2278
1987
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
1988
|
+
}
|
|
1989
|
+
]
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
]
|
|
2281
1993
|
};
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
1994
|
+
const settings = {
|
|
1995
|
+
type: "admin",
|
|
1996
|
+
routes: [
|
|
1997
|
+
{
|
|
1998
|
+
method: "GET",
|
|
1999
|
+
path: "/settings",
|
|
2000
|
+
handler: "settings.find",
|
|
2001
|
+
config: {
|
|
2002
|
+
policies: [
|
|
2003
|
+
"admin::isAuthenticatedAdmin",
|
|
2004
|
+
{
|
|
2005
|
+
name: "admin::hasPermissions",
|
|
2290
2006
|
config: {
|
|
2291
|
-
|
|
2292
|
-
'admin::isAuthenticatedAdmin',
|
|
2293
|
-
{
|
|
2294
|
-
name: 'admin::hasPermissions',
|
|
2295
|
-
config: {
|
|
2296
|
-
actions: [
|
|
2297
|
-
'plugin::content-releases.settings.read'
|
|
2298
|
-
]
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
]
|
|
2007
|
+
actions: ["plugin::content-releases.settings.read"]
|
|
2302
2008
|
}
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2009
|
+
}
|
|
2010
|
+
]
|
|
2011
|
+
}
|
|
2012
|
+
},
|
|
2013
|
+
{
|
|
2014
|
+
method: "PUT",
|
|
2015
|
+
path: "/settings",
|
|
2016
|
+
handler: "settings.update",
|
|
2017
|
+
config: {
|
|
2018
|
+
policies: [
|
|
2019
|
+
"admin::isAuthenticatedAdmin",
|
|
2020
|
+
{
|
|
2021
|
+
name: "admin::hasPermissions",
|
|
2308
2022
|
config: {
|
|
2309
|
-
|
|
2310
|
-
'admin::isAuthenticatedAdmin',
|
|
2311
|
-
{
|
|
2312
|
-
name: 'admin::hasPermissions',
|
|
2313
|
-
config: {
|
|
2314
|
-
actions: [
|
|
2315
|
-
'plugin::content-releases.settings.update'
|
|
2316
|
-
]
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
]
|
|
2023
|
+
actions: ["plugin::content-releases.settings.update"]
|
|
2320
2024
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2025
|
+
}
|
|
2026
|
+
]
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
]
|
|
2323
2030
|
};
|
|
2324
|
-
|
|
2325
2031
|
const routes = {
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2032
|
+
settings,
|
|
2033
|
+
release,
|
|
2034
|
+
"release-action": releaseAction
|
|
2329
2035
|
};
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
if (strapi.ee.features.isEnabled('cms-content-releases')) {
|
|
2333
|
-
return {
|
|
2334
|
-
register,
|
|
2335
|
-
bootstrap,
|
|
2336
|
-
destroy,
|
|
2337
|
-
contentTypes,
|
|
2338
|
-
services,
|
|
2339
|
-
controllers,
|
|
2340
|
-
routes
|
|
2341
|
-
};
|
|
2342
|
-
}
|
|
2036
|
+
const getPlugin = () => {
|
|
2037
|
+
if (strapi.ee.features.isEnabled("cms-content-releases")) {
|
|
2343
2038
|
return {
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2039
|
+
register,
|
|
2040
|
+
bootstrap,
|
|
2041
|
+
destroy,
|
|
2042
|
+
contentTypes,
|
|
2043
|
+
services,
|
|
2044
|
+
controllers,
|
|
2045
|
+
routes
|
|
2348
2046
|
};
|
|
2047
|
+
}
|
|
2048
|
+
return {
|
|
2049
|
+
// Always return register, it handles its own feature check
|
|
2050
|
+
register,
|
|
2051
|
+
// Always return contentTypes to avoid losing data when the feature is disabled
|
|
2052
|
+
contentTypes
|
|
2053
|
+
};
|
|
2349
2054
|
};
|
|
2350
|
-
|
|
2351
|
-
|
|
2055
|
+
const index = getPlugin();
|
|
2352
2056
|
module.exports = index;
|
|
2353
2057
|
//# sourceMappingURL=index.js.map
|