directus 9.15.1 → 9.17.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.
- package/dist/__utils__/items-utils.d.ts +2 -0
- package/dist/__utils__/items-utils.js +36 -0
- package/dist/__utils__/schemas.d.ts +13 -0
- package/dist/__utils__/schemas.js +304 -0
- package/dist/__utils__/snapshots.d.ts +5 -0
- package/dist/__utils__/snapshots.js +897 -0
- package/dist/app.js +8 -7
- package/dist/auth/drivers/ldap.js +1 -0
- package/dist/auth/drivers/local.js +6 -0
- package/dist/auth/drivers/oauth2.js +1 -0
- package/dist/auth/drivers/openid.js +1 -0
- package/dist/cli/index.test.d.ts +1 -0
- package/dist/cli/index.test.js +58 -0
- package/dist/cli/utils/create-env/env-stub.liquid +6 -2
- package/dist/controllers/activity.js +1 -0
- package/dist/controllers/assets.js +20 -16
- package/dist/controllers/auth.js +6 -9
- package/dist/controllers/files.test.d.ts +1 -0
- package/dist/controllers/files.test.js +49 -0
- package/dist/controllers/server.js +0 -1
- package/dist/database/migrations/20220826A-add-origin-to-accountability.d.ts +3 -0
- package/dist/database/migrations/20220826A-add-origin-to-accountability.js +21 -0
- package/dist/database/migrations/run.test.d.ts +1 -0
- package/dist/database/migrations/run.test.js +92 -0
- package/dist/database/system-data/fields/activity.yaml +6 -0
- package/dist/database/system-data/fields/sessions.yaml +2 -0
- package/dist/env.js +15 -0
- package/dist/env.test.d.ts +8 -0
- package/dist/env.test.js +39 -0
- package/dist/extensions.d.ts +1 -0
- package/dist/extensions.js +16 -3
- package/dist/flows.js +28 -17
- package/dist/mailer.js +1 -0
- package/dist/middleware/authenticate.d.ts +1 -1
- package/dist/middleware/authenticate.js +1 -0
- package/dist/middleware/authenticate.test.d.ts +1 -0
- package/dist/middleware/authenticate.test.js +214 -0
- package/dist/middleware/extract-token.test.d.ts +1 -0
- package/dist/middleware/extract-token.test.js +60 -0
- package/dist/middleware/validate-batch.d.ts +1 -2
- package/dist/middleware/validate-batch.js +10 -13
- package/dist/middleware/validate-batch.test.d.ts +1 -0
- package/dist/middleware/validate-batch.test.js +82 -0
- package/dist/operations/exec/index.d.ts +5 -0
- package/dist/operations/exec/index.js +26 -0
- package/dist/operations/exec/index.test.d.ts +1 -0
- package/dist/operations/exec/index.test.js +95 -0
- package/dist/operations/notification/index.js +9 -6
- package/dist/operations/request/index.js +22 -3
- package/dist/operations/transform/index.d.ts +1 -1
- package/dist/operations/transform/index.js +1 -1
- package/dist/services/authentication.js +13 -3
- package/dist/services/files.js +3 -2
- package/dist/services/files.test.d.ts +1 -0
- package/dist/services/files.test.js +53 -0
- package/dist/services/flows.js +4 -0
- package/dist/services/graphql/index.d.ts +2 -2
- package/dist/services/graphql/index.js +78 -75
- package/dist/services/items.js +98 -42
- package/dist/services/items.test.d.ts +1 -0
- package/dist/services/items.test.js +765 -0
- package/dist/services/payload.d.ts +7 -4
- package/dist/services/payload.js +63 -12
- package/dist/services/payload.test.d.ts +1 -0
- package/dist/services/payload.test.js +94 -0
- package/dist/services/server.js +10 -7
- package/dist/services/shares.js +2 -1
- package/dist/services/specifications.test.d.ts +1 -0
- package/dist/services/specifications.test.js +96 -0
- package/dist/types/items.d.ts +11 -0
- package/dist/utils/apply-query.js +7 -3
- package/dist/utils/apply-snapshot.js +15 -0
- package/dist/utils/apply-snapshot.test.d.ts +1 -0
- package/dist/utils/apply-snapshot.test.js +305 -0
- package/dist/utils/async-handler.d.ts +2 -6
- package/dist/utils/async-handler.js +1 -13
- package/dist/utils/async-handler.test.d.ts +1 -0
- package/dist/utils/async-handler.test.js +18 -0
- package/dist/utils/calculate-field-depth.test.d.ts +1 -0
- package/dist/utils/calculate-field-depth.test.js +76 -0
- package/dist/utils/filter-items.test.d.ts +1 -0
- package/dist/utils/filter-items.test.js +60 -0
- package/dist/utils/get-cache-key.test.d.ts +1 -0
- package/dist/utils/get-cache-key.test.js +53 -0
- package/dist/utils/get-column-path.test.d.ts +1 -0
- package/dist/utils/get-column-path.test.js +136 -0
- package/dist/utils/get-config-from-env.test.d.ts +1 -0
- package/dist/utils/get-config-from-env.test.js +19 -0
- package/dist/utils/get-graphql-type.d.ts +1 -1
- package/dist/utils/get-graphql-type.js +4 -1
- package/dist/utils/get-os-info.d.ts +9 -0
- package/dist/utils/get-os-info.js +47 -0
- package/dist/utils/get-relation-info.test.d.ts +1 -0
- package/dist/utils/get-relation-info.test.js +88 -0
- package/dist/utils/get-relation-type.test.d.ts +1 -0
- package/dist/utils/get-relation-type.test.js +69 -0
- package/dist/utils/get-string-byte-size.test.d.ts +1 -0
- package/dist/utils/get-string-byte-size.test.js +8 -0
- package/dist/utils/is-directus-jwt.test.d.ts +1 -0
- package/dist/utils/is-directus-jwt.test.js +26 -0
- package/dist/utils/jwt.test.d.ts +1 -0
- package/dist/utils/jwt.test.js +36 -0
- package/dist/utils/merge-permissions.test.d.ts +1 -0
- package/dist/utils/merge-permissions.test.js +80 -0
- package/dist/utils/validate-keys.test.d.ts +1 -0
- package/dist/utils/validate-keys.test.js +97 -0
- package/package.json +14 -12
package/dist/services/items.js
CHANGED
|
@@ -52,6 +52,7 @@ class ItemsService {
|
|
|
52
52
|
.filter((field) => field.alias === true)
|
|
53
53
|
.map((field) => field.field);
|
|
54
54
|
const payload = (0, lodash_1.cloneDeep)(data);
|
|
55
|
+
const nestedActionEvents = [];
|
|
55
56
|
// By wrapping the logic in a transaction, we make sure we automatically roll back all the
|
|
56
57
|
// changes in the DB if any of the parts contained within throws an error. This also means
|
|
57
58
|
// that any errors thrown in any nested relational changes will bubble up and cancel the whole
|
|
@@ -84,8 +85,8 @@ class ItemsService {
|
|
|
84
85
|
const payloadWithPresets = this.accountability
|
|
85
86
|
? await authorizationService.validatePayload('create', this.collection, payloadAfterHooks)
|
|
86
87
|
: payloadAfterHooks;
|
|
87
|
-
const { payload: payloadWithM2O, revisions: revisionsM2O } = await payloadService.processM2O(payloadWithPresets);
|
|
88
|
-
const { payload: payloadWithA2O, revisions: revisionsA2O } = await payloadService.processA2O(payloadWithM2O);
|
|
88
|
+
const { payload: payloadWithM2O, revisions: revisionsM2O, nestedActionEvents: nestedActionEventsM2O, } = await payloadService.processM2O(payloadWithPresets, opts);
|
|
89
|
+
const { payload: payloadWithA2O, revisions: revisionsA2O, nestedActionEvents: nestedActionEventsA2O, } = await payloadService.processA2O(payloadWithM2O, opts);
|
|
89
90
|
const payloadWithoutAliases = (0, lodash_1.pick)(payloadWithA2O, (0, lodash_1.without)(fields, ...aliases));
|
|
90
91
|
const payloadWithTypeCasting = await payloadService.processValues('create', payloadWithoutAliases);
|
|
91
92
|
// In case of manual string / UUID primary keys, the PK already exists in the object we're saving.
|
|
@@ -113,7 +114,10 @@ class ItemsService {
|
|
|
113
114
|
// to read from it
|
|
114
115
|
payload[primaryKeyField] = primaryKey;
|
|
115
116
|
}
|
|
116
|
-
const { revisions: revisionsO2M } = await payloadService.processO2M(payload, primaryKey);
|
|
117
|
+
const { revisions: revisionsO2M, nestedActionEvents: nestedActionEventsO2M } = await payloadService.processO2M(payload, primaryKey, opts);
|
|
118
|
+
nestedActionEvents.push(...nestedActionEventsM2O);
|
|
119
|
+
nestedActionEvents.push(...nestedActionEventsA2O);
|
|
120
|
+
nestedActionEvents.push(...nestedActionEventsO2M);
|
|
117
121
|
// If this is an authenticated action, and accountability tracking is enabled, save activity row
|
|
118
122
|
if (this.accountability && this.schema.collections[this.collection].accountability !== null) {
|
|
119
123
|
const activityService = new index_1.ActivityService({
|
|
@@ -126,6 +130,7 @@ class ItemsService {
|
|
|
126
130
|
collection: this.collection,
|
|
127
131
|
ip: this.accountability.ip,
|
|
128
132
|
user_agent: this.accountability.userAgent,
|
|
133
|
+
origin: this.accountability.origin,
|
|
129
134
|
item: primaryKey,
|
|
130
135
|
});
|
|
131
136
|
// If revisions are tracked, create revisions record
|
|
@@ -154,17 +159,30 @@ class ItemsService {
|
|
|
154
159
|
return primaryKey;
|
|
155
160
|
});
|
|
156
161
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
162
|
+
const actionEvent = {
|
|
163
|
+
event: this.eventScope === 'items'
|
|
164
|
+
? ['items.create', `${this.collection}.items.create`]
|
|
165
|
+
: `${this.eventScope}.create`,
|
|
166
|
+
meta: {
|
|
167
|
+
payload,
|
|
168
|
+
key: primaryKey,
|
|
169
|
+
collection: this.collection,
|
|
170
|
+
},
|
|
171
|
+
context: {
|
|
172
|
+
database: (0, database_1.default)(),
|
|
173
|
+
schema: this.schema,
|
|
174
|
+
accountability: this.accountability,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
if (!(opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction)) {
|
|
178
|
+
emitter_1.default.emitAction(actionEvent.event, actionEvent.meta, actionEvent.context);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
opts.bypassEmitAction(actionEvent);
|
|
182
|
+
}
|
|
183
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
184
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
185
|
+
}
|
|
168
186
|
}
|
|
169
187
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
170
188
|
await this.cache.clear();
|
|
@@ -197,7 +215,16 @@ class ItemsService {
|
|
|
197
215
|
* Get items by query
|
|
198
216
|
*/
|
|
199
217
|
async readByQuery(query, opts) {
|
|
200
|
-
|
|
218
|
+
const updatedQuery = (opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false
|
|
219
|
+
? await emitter_1.default.emitFilter(`${this.eventScope}.query`, query, {
|
|
220
|
+
collection: this.collection,
|
|
221
|
+
}, {
|
|
222
|
+
database: this.knex,
|
|
223
|
+
schema: this.schema,
|
|
224
|
+
accountability: this.accountability,
|
|
225
|
+
})
|
|
226
|
+
: query;
|
|
227
|
+
let ast = await (0, get_ast_from_query_1.default)(this.collection, updatedQuery, this.schema, {
|
|
201
228
|
accountability: this.accountability,
|
|
202
229
|
// By setting the permissions action, you can read items using the permissions for another
|
|
203
230
|
// operation's permissions. This is used to dynamically check if you have update/delete
|
|
@@ -223,7 +250,7 @@ class ItemsService {
|
|
|
223
250
|
}
|
|
224
251
|
const filteredRecords = (opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false
|
|
225
252
|
? await emitter_1.default.emitFilter(this.eventScope === 'items' ? ['items.read', `${this.collection}.items.read`] : `${this.eventScope}.read`, records, {
|
|
226
|
-
query,
|
|
253
|
+
query: updatedQuery,
|
|
227
254
|
collection: this.collection,
|
|
228
255
|
}, {
|
|
229
256
|
database: this.knex,
|
|
@@ -234,7 +261,7 @@ class ItemsService {
|
|
|
234
261
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false) {
|
|
235
262
|
emitter_1.default.emitAction(this.eventScope === 'items' ? ['items.read', `${this.collection}.items.read`] : `${this.eventScope}.read`, {
|
|
236
263
|
payload: filteredRecords,
|
|
237
|
-
query,
|
|
264
|
+
query: updatedQuery,
|
|
238
265
|
collection: this.collection,
|
|
239
266
|
}, {
|
|
240
267
|
database: this.knex || (0, database_1.default)(),
|
|
@@ -323,6 +350,7 @@ class ItemsService {
|
|
|
323
350
|
.filter((field) => field.alias === true)
|
|
324
351
|
.map((field) => field.field);
|
|
325
352
|
const payload = (0, lodash_1.cloneDeep)(data);
|
|
353
|
+
const nestedActionEvents = [];
|
|
326
354
|
const authorizationService = new authorization_1.AuthorizationService({
|
|
327
355
|
accountability: this.accountability,
|
|
328
356
|
knex: this.knex,
|
|
@@ -356,8 +384,8 @@ class ItemsService {
|
|
|
356
384
|
knex: trx,
|
|
357
385
|
schema: this.schema,
|
|
358
386
|
});
|
|
359
|
-
const { payload: payloadWithM2O, revisions: revisionsM2O } = await payloadService.processM2O(payloadWithPresets);
|
|
360
|
-
const { payload: payloadWithA2O, revisions: revisionsA2O } = await payloadService.processA2O(payloadWithM2O);
|
|
387
|
+
const { payload: payloadWithM2O, revisions: revisionsM2O, nestedActionEvents: nestedActionEventsM2O, } = await payloadService.processM2O(payloadWithPresets, opts);
|
|
388
|
+
const { payload: payloadWithA2O, revisions: revisionsA2O, nestedActionEvents: nestedActionEventsA2O, } = await payloadService.processA2O(payloadWithM2O, opts);
|
|
361
389
|
const payloadWithoutAliasAndPK = (0, lodash_1.pick)(payloadWithA2O, (0, lodash_1.without)(fields, primaryKeyField, ...aliases));
|
|
362
390
|
const payloadWithTypeCasting = await payloadService.processValues('update', payloadWithoutAliasAndPK);
|
|
363
391
|
if (Object.keys(payloadWithTypeCasting).length > 0) {
|
|
@@ -369,9 +397,12 @@ class ItemsService {
|
|
|
369
397
|
}
|
|
370
398
|
}
|
|
371
399
|
const childrenRevisions = [...revisionsM2O, ...revisionsA2O];
|
|
400
|
+
nestedActionEvents.push(...nestedActionEventsM2O);
|
|
401
|
+
nestedActionEvents.push(...nestedActionEventsA2O);
|
|
372
402
|
for (const key of keys) {
|
|
373
|
-
const { revisions } = await payloadService.processO2M(payload, key);
|
|
403
|
+
const { revisions, nestedActionEvents: nestedActionEventsO2M } = await payloadService.processO2M(payload, key, opts);
|
|
374
404
|
childrenRevisions.push(...revisions);
|
|
405
|
+
nestedActionEvents.push(...nestedActionEventsO2M);
|
|
375
406
|
}
|
|
376
407
|
// If this is an authenticated action, and accountability tracking is enabled, save activity row
|
|
377
408
|
if (this.accountability && this.schema.collections[this.collection].accountability !== null) {
|
|
@@ -385,6 +416,7 @@ class ItemsService {
|
|
|
385
416
|
collection: this.collection,
|
|
386
417
|
ip: this.accountability.ip,
|
|
387
418
|
user_agent: this.accountability.userAgent,
|
|
419
|
+
origin: this.accountability.origin,
|
|
388
420
|
item: key,
|
|
389
421
|
})));
|
|
390
422
|
if (this.schema.collections[this.collection].accountability === 'all') {
|
|
@@ -427,17 +459,30 @@ class ItemsService {
|
|
|
427
459
|
await this.cache.clear();
|
|
428
460
|
}
|
|
429
461
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
462
|
+
const actionEvent = {
|
|
463
|
+
event: this.eventScope === 'items'
|
|
464
|
+
? ['items.update', `${this.collection}.items.update`]
|
|
465
|
+
: `${this.eventScope}.update`,
|
|
466
|
+
meta: {
|
|
467
|
+
payload,
|
|
468
|
+
keys,
|
|
469
|
+
collection: this.collection,
|
|
470
|
+
},
|
|
471
|
+
context: {
|
|
472
|
+
database: (0, database_1.default)(),
|
|
473
|
+
schema: this.schema,
|
|
474
|
+
accountability: this.accountability,
|
|
475
|
+
},
|
|
476
|
+
};
|
|
477
|
+
if (!(opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction)) {
|
|
478
|
+
emitter_1.default.emitAction(actionEvent.event, actionEvent.meta, actionEvent.context);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
opts.bypassEmitAction(actionEvent);
|
|
482
|
+
}
|
|
483
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
484
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
485
|
+
}
|
|
441
486
|
}
|
|
442
487
|
return keys;
|
|
443
488
|
}
|
|
@@ -539,6 +584,7 @@ class ItemsService {
|
|
|
539
584
|
collection: this.collection,
|
|
540
585
|
ip: this.accountability.ip,
|
|
541
586
|
user_agent: this.accountability.userAgent,
|
|
587
|
+
origin: this.accountability.origin,
|
|
542
588
|
item: key,
|
|
543
589
|
})));
|
|
544
590
|
}
|
|
@@ -547,17 +593,27 @@ class ItemsService {
|
|
|
547
593
|
await this.cache.clear();
|
|
548
594
|
}
|
|
549
595
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
596
|
+
const actionEvent = {
|
|
597
|
+
event: this.eventScope === 'items'
|
|
598
|
+
? ['items.delete', `${this.collection}.items.delete`]
|
|
599
|
+
: `${this.eventScope}.delete`,
|
|
600
|
+
meta: {
|
|
601
|
+
payload: keys,
|
|
602
|
+
keys: keys,
|
|
603
|
+
collection: this.collection,
|
|
604
|
+
},
|
|
605
|
+
context: {
|
|
606
|
+
database: (0, database_1.default)(),
|
|
607
|
+
schema: this.schema,
|
|
608
|
+
accountability: this.accountability,
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
if (!(opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction)) {
|
|
612
|
+
emitter_1.default.emitAction(actionEvent.event, actionEvent.meta, actionEvent.context);
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
opts.bypassEmitAction(actionEvent);
|
|
616
|
+
}
|
|
561
617
|
}
|
|
562
618
|
return keys;
|
|
563
619
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|