@strapi/strapi 4.11.0-beta.0 → 4.11.0-exp.0
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { cloneDeep } = require('lodash/fp');
|
|
4
4
|
const _ = require('lodash');
|
|
5
|
-
const { hasDraftAndPublish
|
|
5
|
+
const { hasDraftAndPublish } = require('@strapi/utils').contentTypes;
|
|
6
6
|
const {
|
|
7
7
|
CREATED_AT_ATTRIBUTE,
|
|
8
8
|
UPDATED_AT_ATTRIBUTE,
|
|
@@ -58,12 +58,6 @@ const createContentType = (uid, definition) => {
|
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
Object.defineProperty(schema, 'privateAttributes', {
|
|
62
|
-
get() {
|
|
63
|
-
return getPrivateAttributes(schema);
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
61
|
// attributes
|
|
68
62
|
Object.assign(schema.attributes, {
|
|
69
63
|
[CREATED_AT_ATTRIBUTE]: {
|
|
@@ -4,11 +4,7 @@ const _ = require('lodash');
|
|
|
4
4
|
const delegate = require('delegates');
|
|
5
5
|
const { InvalidTimeError, InvalidDateError, InvalidDateTimeError, InvalidRelationError } =
|
|
6
6
|
require('@strapi/database').errors;
|
|
7
|
-
const {
|
|
8
|
-
webhook: webhookUtils,
|
|
9
|
-
contentTypes: contentTypesUtils,
|
|
10
|
-
sanitize,
|
|
11
|
-
} = require('@strapi/utils');
|
|
7
|
+
const { contentTypes: contentTypesUtils, sanitize } = require('@strapi/utils');
|
|
12
8
|
const { ValidationError } = require('@strapi/utils').errors;
|
|
13
9
|
const { isAnyToMany } = require('@strapi/utils').relations;
|
|
14
10
|
const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams;
|
|
@@ -31,9 +27,6 @@ const transformLoadParamsToQuery = (uid, field, params = {}, pagination = {}) =>
|
|
|
31
27
|
};
|
|
32
28
|
};
|
|
33
29
|
|
|
34
|
-
// TODO: those should be strapi events used by the webhooks not the other way arround
|
|
35
|
-
const { ENTRY_CREATE, ENTRY_UPDATE, ENTRY_DELETE } = webhookUtils.webhookEvents;
|
|
36
|
-
|
|
37
30
|
const databaseErrorsToTransform = [
|
|
38
31
|
InvalidTimeError,
|
|
39
32
|
InvalidDateTimeError,
|
|
@@ -49,6 +42,12 @@ const updatePipeline = (data, context) => {
|
|
|
49
42
|
return applyTransforms(data, context);
|
|
50
43
|
};
|
|
51
44
|
|
|
45
|
+
const ALLOWED_WEBHOOK_EVENTS = {
|
|
46
|
+
ENTRY_CREATE: 'entry.create',
|
|
47
|
+
ENTRY_UPDATE: 'entry.update',
|
|
48
|
+
ENTRY_DELETE: 'entry.delete',
|
|
49
|
+
};
|
|
50
|
+
|
|
52
51
|
/**
|
|
53
52
|
* @type {import('.').default}
|
|
54
53
|
*/
|
|
@@ -59,6 +58,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
59
58
|
return options;
|
|
60
59
|
},
|
|
61
60
|
|
|
61
|
+
async wrapResult(result) {
|
|
62
|
+
return result;
|
|
63
|
+
},
|
|
64
|
+
|
|
62
65
|
async emitEvent(uid, event, entity) {
|
|
63
66
|
// Ignore audit log events to prevent infinite loops
|
|
64
67
|
if (uid === 'admin::audit-log') {
|
|
@@ -83,10 +86,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
83
86
|
const query = transformParamsToQuery(uid, wrappedParams);
|
|
84
87
|
|
|
85
88
|
if (kind === 'singleType') {
|
|
86
|
-
|
|
89
|
+
const entity = db.query(uid).findOne(query);
|
|
90
|
+
return this.wrapResult(entity, { uid, action: 'findOne' });
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
const entities = await db.query(uid).findMany(query);
|
|
94
|
+
return this.wrapResult(entities, { uid, action: 'findMany' });
|
|
90
95
|
},
|
|
91
96
|
|
|
92
97
|
async findPage(uid, opts) {
|
|
@@ -94,7 +99,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
94
99
|
|
|
95
100
|
const query = transformParamsToQuery(uid, wrappedParams);
|
|
96
101
|
|
|
97
|
-
|
|
102
|
+
const page = await db.query(uid).findPage(query);
|
|
103
|
+
return {
|
|
104
|
+
...page,
|
|
105
|
+
results: await this.wrapResult(page.results, { uid, action: 'findPage' }),
|
|
106
|
+
};
|
|
98
107
|
},
|
|
99
108
|
|
|
100
109
|
// TODO: streamline the logic based on the populate option
|
|
@@ -103,7 +112,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
103
112
|
|
|
104
113
|
const query = transformParamsToQuery(uid, wrappedParams);
|
|
105
114
|
|
|
106
|
-
|
|
115
|
+
const entities = await db.query(uid).findPage(query);
|
|
116
|
+
return {
|
|
117
|
+
...entities,
|
|
118
|
+
results: await this.wrapResult(entities.results, { uid, action: 'findWithRelationCounts' }),
|
|
119
|
+
};
|
|
107
120
|
},
|
|
108
121
|
|
|
109
122
|
async findWithRelationCounts(uid, opts) {
|
|
@@ -111,7 +124,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
111
124
|
|
|
112
125
|
const query = transformParamsToQuery(uid, wrappedParams);
|
|
113
126
|
|
|
114
|
-
|
|
127
|
+
const entities = await db.query(uid).findMany(query);
|
|
128
|
+
return this.wrapResult(entities, { uid, action: 'findWithRelationCounts' });
|
|
115
129
|
},
|
|
116
130
|
|
|
117
131
|
async findOne(uid, entityId, opts) {
|
|
@@ -119,7 +133,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
119
133
|
|
|
120
134
|
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
121
135
|
|
|
122
|
-
|
|
136
|
+
const entity = await db.query(uid).findOne({ ...query, where: { id: entityId } });
|
|
137
|
+
return this.wrapResult(entity, { uid, action: 'findOne' });
|
|
123
138
|
},
|
|
124
139
|
|
|
125
140
|
async count(uid, opts) {
|
|
@@ -162,6 +177,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
162
177
|
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
163
178
|
}
|
|
164
179
|
|
|
180
|
+
entity = await this.wrapResult(entity, { uid, action: 'create' });
|
|
181
|
+
|
|
182
|
+
const { ENTRY_CREATE } = ALLOWED_WEBHOOK_EVENTS;
|
|
165
183
|
await this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
166
184
|
|
|
167
185
|
return entity;
|
|
@@ -213,6 +231,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
213
231
|
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
214
232
|
}
|
|
215
233
|
|
|
234
|
+
entity = await this.wrapResult(entity, { uid, action: 'update' });
|
|
235
|
+
|
|
236
|
+
const { ENTRY_UPDATE } = ALLOWED_WEBHOOK_EVENTS;
|
|
216
237
|
await this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
217
238
|
|
|
218
239
|
return entity;
|
|
@@ -224,7 +245,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
224
245
|
// select / populate
|
|
225
246
|
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
226
247
|
|
|
227
|
-
|
|
248
|
+
let entityToDelete = await db.query(uid).findOne({
|
|
228
249
|
...query,
|
|
229
250
|
where: { id: entityId },
|
|
230
251
|
});
|
|
@@ -238,6 +259,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
238
259
|
await db.query(uid).delete({ where: { id: entityToDelete.id } });
|
|
239
260
|
await deleteComponents(uid, componentsToDelete, { loadComponents: false });
|
|
240
261
|
|
|
262
|
+
entityToDelete = await this.wrapResult(entityToDelete, { uid, action: 'delete' });
|
|
263
|
+
|
|
264
|
+
const { ENTRY_DELETE } = ALLOWED_WEBHOOK_EVENTS;
|
|
241
265
|
await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
242
266
|
|
|
243
267
|
return entityToDelete;
|
|
@@ -250,7 +274,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
250
274
|
// select / populate
|
|
251
275
|
const query = transformParamsToQuery(uid, wrappedParams);
|
|
252
276
|
|
|
253
|
-
|
|
277
|
+
let entitiesToDelete = await db.query(uid).findMany(query);
|
|
254
278
|
|
|
255
279
|
if (!entitiesToDelete.length) {
|
|
256
280
|
return null;
|
|
@@ -265,21 +289,28 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
265
289
|
componentsToDelete.map((compos) => deleteComponents(uid, compos, { loadComponents: false }))
|
|
266
290
|
);
|
|
267
291
|
|
|
292
|
+
entitiesToDelete = await this.wrapResult(entitiesToDelete, { uid, action: 'delete' });
|
|
293
|
+
|
|
268
294
|
// Trigger webhooks. One for each entity
|
|
295
|
+
const { ENTRY_DELETE } = ALLOWED_WEBHOOK_EVENTS;
|
|
269
296
|
await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity)));
|
|
270
297
|
|
|
271
298
|
return deletedEntities;
|
|
272
299
|
},
|
|
273
300
|
|
|
274
|
-
load(uid, entity, field, params = {}) {
|
|
301
|
+
async load(uid, entity, field, params = {}) {
|
|
275
302
|
if (!_.isString(field)) {
|
|
276
303
|
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
|
277
304
|
}
|
|
278
305
|
|
|
279
|
-
|
|
306
|
+
const loadedEntity = await db
|
|
307
|
+
.query(uid)
|
|
308
|
+
.load(entity, field, transformLoadParamsToQuery(uid, field, params));
|
|
309
|
+
|
|
310
|
+
return this.wrapResult(loadedEntity, { uid, field, action: 'load' });
|
|
280
311
|
},
|
|
281
312
|
|
|
282
|
-
loadPages(uid, entity, field, params = {}, pagination = {}) {
|
|
313
|
+
async loadPages(uid, entity, field, params = {}, pagination = {}) {
|
|
283
314
|
if (!_.isString(field)) {
|
|
284
315
|
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
|
285
316
|
}
|
|
@@ -293,11 +324,20 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
293
324
|
|
|
294
325
|
const query = transformLoadParamsToQuery(uid, field, params, pagination);
|
|
295
326
|
|
|
296
|
-
|
|
327
|
+
const loadedPage = await db.query(uid).loadPages(entity, field, query);
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
...loadedPage,
|
|
331
|
+
results: await this.wrapResult(loadedPage.results, { uid, field, action: 'load' }),
|
|
332
|
+
};
|
|
297
333
|
},
|
|
298
334
|
});
|
|
299
335
|
|
|
300
336
|
module.exports = (ctx) => {
|
|
337
|
+
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
338
|
+
ctx.strapi.webhookStore.addAllowedEvent(key, value);
|
|
339
|
+
});
|
|
340
|
+
|
|
301
341
|
const implementation = createDefaultImplementation(ctx);
|
|
302
342
|
|
|
303
343
|
const service = {
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
+
const { mapAsync } = require('@strapi/utils');
|
|
8
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
9
|
+
|
|
7
10
|
const webhookModel = {
|
|
8
11
|
uid: 'webhook',
|
|
9
12
|
collectionName: 'strapi_webhooks',
|
|
@@ -47,30 +50,56 @@ const fromDBObject = (row) => {
|
|
|
47
50
|
};
|
|
48
51
|
};
|
|
49
52
|
|
|
53
|
+
const webhookEventValidator = async (allowedEvents, events) => {
|
|
54
|
+
const allowedValues = Array.from(allowedEvents.values());
|
|
55
|
+
|
|
56
|
+
await mapAsync(events, (event) => {
|
|
57
|
+
if (allowedValues.includes(event)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new ValidationError(`Webhook event ${event} is not supported`);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
50
65
|
const createWebhookStore = ({ db }) => {
|
|
51
66
|
const webhookQueries = db.query('webhook');
|
|
52
67
|
|
|
53
68
|
return {
|
|
69
|
+
allowedEvents: new Map([]),
|
|
70
|
+
addAllowedEvent(key, value) {
|
|
71
|
+
this.allowedEvents.set(key, value);
|
|
72
|
+
},
|
|
73
|
+
removeAllowedEvent(key) {
|
|
74
|
+
this.allowedEvents.delete(key);
|
|
75
|
+
},
|
|
76
|
+
listAllowedEvents() {
|
|
77
|
+
return Array.from(this.allowedEvents.keys());
|
|
78
|
+
},
|
|
79
|
+
getAllowedEvent(key) {
|
|
80
|
+
return this.allowedEvents.get(key);
|
|
81
|
+
},
|
|
54
82
|
async findWebhooks() {
|
|
55
83
|
const results = await webhookQueries.findMany();
|
|
56
84
|
|
|
57
85
|
return results.map(fromDBObject);
|
|
58
86
|
},
|
|
59
|
-
|
|
60
87
|
async findWebhook(id) {
|
|
61
88
|
const result = await webhookQueries.findOne({ where: { id } });
|
|
62
89
|
return result ? fromDBObject(result) : null;
|
|
63
90
|
},
|
|
91
|
+
async createWebhook(data) {
|
|
92
|
+
await webhookEventValidator(this.allowedEvents, data.events);
|
|
64
93
|
|
|
65
|
-
createWebhook(data) {
|
|
66
94
|
return webhookQueries
|
|
67
95
|
.create({
|
|
68
96
|
data: toDBObject({ ...data, isEnabled: true }),
|
|
69
97
|
})
|
|
70
98
|
.then(fromDBObject);
|
|
71
99
|
},
|
|
72
|
-
|
|
73
100
|
async updateWebhook(id, data) {
|
|
101
|
+
await webhookEventValidator(this.allowedEvents, data.events);
|
|
102
|
+
|
|
74
103
|
const webhook = await webhookQueries.update({
|
|
75
104
|
where: { id },
|
|
76
105
|
data: toDBObject(data),
|
|
@@ -78,7 +107,6 @@ const createWebhookStore = ({ db }) => {
|
|
|
78
107
|
|
|
79
108
|
return webhook ? fromDBObject(webhook) : null;
|
|
80
109
|
},
|
|
81
|
-
|
|
82
110
|
async deleteWebhook(id) {
|
|
83
111
|
const webhook = await webhookQueries.delete({ where: { id } });
|
|
84
112
|
return webhook ? fromDBObject(webhook) : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/strapi",
|
|
3
|
-
"version": "4.11.0-
|
|
3
|
+
"version": "4.11.0-exp.0",
|
|
4
4
|
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -81,19 +81,19 @@
|
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"@koa/cors": "3.4.3",
|
|
83
83
|
"@koa/router": "10.1.1",
|
|
84
|
-
"@strapi/admin": "4.11.0-
|
|
85
|
-
"@strapi/data-transfer": "4.11.0-
|
|
86
|
-
"@strapi/database": "4.11.0-
|
|
87
|
-
"@strapi/generate-new": "4.11.0-
|
|
88
|
-
"@strapi/generators": "4.11.0-
|
|
89
|
-
"@strapi/logger": "4.11.0-
|
|
90
|
-
"@strapi/permissions": "4.11.0-
|
|
91
|
-
"@strapi/plugin-content-manager": "4.11.0-
|
|
92
|
-
"@strapi/plugin-content-type-builder": "4.11.0-
|
|
93
|
-
"@strapi/plugin-email": "4.11.0-
|
|
94
|
-
"@strapi/plugin-upload": "4.11.0-
|
|
95
|
-
"@strapi/typescript-utils": "4.11.0-
|
|
96
|
-
"@strapi/utils": "4.11.0-
|
|
84
|
+
"@strapi/admin": "4.11.0-exp.0",
|
|
85
|
+
"@strapi/data-transfer": "4.11.0-exp.0",
|
|
86
|
+
"@strapi/database": "4.11.0-exp.0",
|
|
87
|
+
"@strapi/generate-new": "4.11.0-exp.0",
|
|
88
|
+
"@strapi/generators": "4.11.0-exp.0",
|
|
89
|
+
"@strapi/logger": "4.11.0-exp.0",
|
|
90
|
+
"@strapi/permissions": "4.11.0-exp.0",
|
|
91
|
+
"@strapi/plugin-content-manager": "4.11.0-exp.0",
|
|
92
|
+
"@strapi/plugin-content-type-builder": "4.11.0-exp.0",
|
|
93
|
+
"@strapi/plugin-email": "4.11.0-exp.0",
|
|
94
|
+
"@strapi/plugin-upload": "4.11.0-exp.0",
|
|
95
|
+
"@strapi/typescript-utils": "4.11.0-exp.0",
|
|
96
|
+
"@strapi/utils": "4.11.0-exp.0",
|
|
97
97
|
"bcryptjs": "2.4.3",
|
|
98
98
|
"boxen": "5.1.2",
|
|
99
99
|
"chalk": "4.1.2",
|
|
@@ -136,11 +136,11 @@
|
|
|
136
136
|
},
|
|
137
137
|
"devDependencies": {
|
|
138
138
|
"supertest": "6.3.3",
|
|
139
|
-
"typescript": "5.
|
|
139
|
+
"typescript": "5.1.3"
|
|
140
140
|
},
|
|
141
141
|
"engines": {
|
|
142
142
|
"node": ">=14.19.1 <=18.x.x",
|
|
143
143
|
"npm": ">=6.0.0"
|
|
144
144
|
},
|
|
145
|
-
"gitHead": "
|
|
145
|
+
"gitHead": "8357aab46ebea3565c44744eb137ed36602a4306"
|
|
146
146
|
}
|