directus 9.20.4 → 9.21.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/cli/utils/create-db-connection.d.ts +1 -1
- package/dist/controllers/extensions.js +4 -13
- package/dist/database/helpers/date/dialects/sqlite.d.ts +1 -1
- package/dist/database/helpers/date/dialects/sqlite.js +4 -0
- package/dist/database/helpers/date/types.d.ts +1 -1
- package/dist/database/helpers/date/types.js +4 -0
- package/dist/database/helpers/fn/dialects/mssql.d.ts +8 -8
- package/dist/database/helpers/fn/dialects/mssql.js +22 -16
- package/dist/database/helpers/fn/dialects/mysql.d.ts +8 -8
- package/dist/database/helpers/fn/dialects/mysql.js +22 -16
- package/dist/database/helpers/fn/dialects/postgres.d.ts +8 -8
- package/dist/database/helpers/fn/dialects/postgres.js +22 -16
- package/dist/database/helpers/fn/types.d.ts +1 -1
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.js +11 -0
- package/dist/database/helpers/schema/types.d.ts +3 -2
- package/dist/database/helpers/schema/types.js +5 -0
- package/dist/database/migrations/run.js +29 -3
- package/dist/database/run-ast.d.ts +1 -1
- package/dist/database/run-ast.js +1 -1
- package/dist/env.d.ts +4 -0
- package/dist/env.js +9 -4
- package/dist/env.test.d.ts +1 -8
- package/dist/exceptions/database/contains-null-values.d.ts +1 -1
- package/dist/exceptions/database/dialects/types.d.ts +6 -6
- package/dist/exceptions/database/invalid-foreign-key.d.ts +1 -1
- package/dist/exceptions/database/not-null-violation.d.ts +1 -1
- package/dist/exceptions/database/record-not-unique.d.ts +1 -1
- package/dist/exceptions/database/value-out-of-range.d.ts +1 -1
- package/dist/exceptions/database/value-too-long.d.ts +1 -1
- package/dist/exceptions/hit-rate-limit.d.ts +1 -1
- package/dist/exceptions/method-not-allowed.d.ts +1 -1
- package/dist/exceptions/service-unavailable.d.ts +1 -1
- package/dist/extensions.d.ts +7 -7
- package/dist/extensions.js +92 -89
- package/dist/logger.d.ts +1 -0
- package/dist/messenger.d.ts +1 -1
- package/dist/middleware/authenticate.d.ts +1 -0
- package/dist/middleware/validate-batch.d.ts +2 -0
- package/dist/operations/condition/index.d.ts +1 -1
- package/dist/operations/condition/index.js +1 -1
- package/dist/operations/condition/index.test.d.ts +1 -0
- package/dist/operations/exec/index.d.ts +1 -1
- package/dist/operations/item-create/index.d.ts +1 -1
- package/dist/operations/item-delete/index.d.ts +1 -1
- package/dist/operations/item-read/index.d.ts +1 -1
- package/dist/operations/item-update/index.d.ts +1 -1
- package/dist/operations/log/index.d.ts +1 -1
- package/dist/operations/mail/index.d.ts +1 -1
- package/dist/operations/notification/index.d.ts +1 -1
- package/dist/operations/request/index.d.ts +1 -1
- package/dist/operations/sleep/index.d.ts +1 -1
- package/dist/operations/transform/index.d.ts +1 -1
- package/dist/operations/trigger/index.d.ts +1 -1
- package/dist/operations/trigger/index.js +5 -2
- package/dist/rate-limiter.d.ts +1 -1
- package/dist/services/authorization.js +7 -3
- package/dist/services/collections.d.ts +1 -1
- package/dist/services/collections.js +112 -13
- package/dist/services/fields.d.ts +2 -2
- package/dist/services/fields.js +89 -41
- package/dist/services/fields.test.d.ts +1 -0
- package/dist/services/graphql/index.js +4 -1
- package/dist/services/graphql/utils/process-error.d.ts +4 -0
- package/dist/services/graphql/utils/process-error.js +26 -0
- package/dist/services/graphql/utils/process-error.test.d.ts +1 -0
- package/dist/services/items.d.ts +1 -1
- package/dist/services/items.js +39 -13
- package/dist/services/mail/index.d.ts +2 -2
- package/dist/services/mail/index.js +2 -1
- package/dist/services/mail/templates/base.liquid +4 -4
- package/dist/services/notifications.js +9 -4
- package/dist/services/notifications.test.d.ts +1 -0
- package/dist/services/payload.d.ts +2 -2
- package/dist/services/payload.js +14 -12
- package/dist/services/relations.d.ts +2 -2
- package/dist/services/relations.js +54 -4
- package/dist/services/users.js +2 -2
- package/dist/services/users.test.d.ts +1 -0
- package/dist/types/assets.d.ts +7 -7
- package/dist/types/ast.d.ts +7 -7
- package/dist/types/auth.d.ts +4 -4
- package/dist/types/collection.d.ts +2 -2
- package/dist/types/events.d.ts +1 -1
- package/dist/types/files.d.ts +2 -2
- package/dist/types/items.d.ts +5 -5
- package/dist/types/migration.d.ts +1 -1
- package/dist/types/revision.d.ts +1 -1
- package/dist/types/services.d.ts +1 -1
- package/dist/types/snapshot.d.ts +4 -4
- package/dist/types/webhooks.d.ts +2 -2
- package/dist/utils/get-ast-from-query.d.ts +1 -1
- package/dist/utils/get-column-path.d.ts +2 -2
- package/dist/utils/get-module-default.d.ts +1 -1
- package/dist/utils/get-relation-info.d.ts +1 -1
- package/dist/utils/job-queue.d.ts +1 -1
- package/dist/utils/merge-permissions.d.ts +1 -0
- package/dist/utils/reduce-schema.js +3 -1
- package/package.json +70 -71
- package/dist/__mocks__/cache.d.ts +0 -5
- package/dist/__mocks__/cache.js +0 -7
- package/dist/__utils__/items-utils.d.ts +0 -2
- package/dist/__utils__/items-utils.js +0 -36
- package/dist/__utils__/schemas.d.ts +0 -13
- package/dist/__utils__/schemas.js +0 -304
- package/dist/__utils__/snapshots.d.ts +0 -5
- package/dist/__utils__/snapshots.js +0 -897
- package/dist/cli/index.test.js +0 -63
- package/dist/controllers/files.test.js +0 -49
- package/dist/database/migrations/run.test.js +0 -92
- package/dist/env.test.js +0 -40
- package/dist/middleware/authenticate.test.js +0 -214
- package/dist/middleware/extract-token.test.js +0 -60
- package/dist/middleware/validate-batch.test.js +0 -82
- package/dist/operations/exec/index.test.js +0 -95
- package/dist/services/files.test.js +0 -89
- package/dist/services/items.test.js +0 -765
- package/dist/services/payload.test.js +0 -196
- package/dist/services/specifications.test.js +0 -96
- package/dist/utils/apply-snapshot.test.js +0 -305
- package/dist/utils/async-handler.test.js +0 -18
- package/dist/utils/calculate-field-depth.test.js +0 -76
- package/dist/utils/filter-items.test.js +0 -60
- package/dist/utils/get-auth-providers.test.js +0 -72
- package/dist/utils/get-cache-key.test.js +0 -74
- package/dist/utils/get-column-path.test.js +0 -136
- package/dist/utils/get-config-from-env.test.js +0 -19
- package/dist/utils/get-relation-info.test.js +0 -88
- package/dist/utils/get-relation-type.test.js +0 -69
- package/dist/utils/get-string-byte-size.test.js +0 -8
- package/dist/utils/is-directus-jwt.test.js +0 -26
- package/dist/utils/jwt.test.js +0 -36
- package/dist/utils/merge-permissions.test.js +0 -80
- package/dist/utils/validate-keys.test.js +0 -97
|
@@ -39,6 +39,8 @@ const items_1 = require("../services/items");
|
|
|
39
39
|
const utils_1 = require("@directus/shared/utils");
|
|
40
40
|
const helpers_1 = require("../database/helpers");
|
|
41
41
|
const lodash_1 = require("lodash");
|
|
42
|
+
const get_schema_1 = require("../utils/get-schema");
|
|
43
|
+
const emitter_1 = __importDefault(require("../emitter"));
|
|
42
44
|
class CollectionsService {
|
|
43
45
|
constructor(options) {
|
|
44
46
|
this.knex = options.knex || (0, database_1.default)();
|
|
@@ -63,6 +65,7 @@ class CollectionsService {
|
|
|
63
65
|
if (payload.collection.startsWith('directus_')) {
|
|
64
66
|
throw new exceptions_1.InvalidPayloadException(`Collections can't start with "directus_"`);
|
|
65
67
|
}
|
|
68
|
+
const nestedActionEvents = [];
|
|
66
69
|
try {
|
|
67
70
|
const existingCollections = [
|
|
68
71
|
...((_b = (_a = (await this.knex.select('collection').from('directus_collections'))) === null || _a === void 0 ? void 0 : _a.map(({ collection }) => collection)) !== null && _b !== void 0 ? _b : []),
|
|
@@ -125,7 +128,9 @@ class CollectionsService {
|
|
|
125
128
|
schema: this.schema,
|
|
126
129
|
});
|
|
127
130
|
const fieldPayloads = payload.fields.filter((field) => field.meta).map((field) => field.meta);
|
|
128
|
-
await fieldItemsService.createMany(fieldPayloads
|
|
131
|
+
await fieldItemsService.createMany(fieldPayloads, {
|
|
132
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
133
|
+
});
|
|
129
134
|
}
|
|
130
135
|
if (payload.meta) {
|
|
131
136
|
const collectionItemsService = new items_1.ItemsService('directus_collections', {
|
|
@@ -136,6 +141,8 @@ class CollectionsService {
|
|
|
136
141
|
await collectionItemsService.createOne({
|
|
137
142
|
...payload.meta,
|
|
138
143
|
collection: payload.collection,
|
|
144
|
+
}, {
|
|
145
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
139
146
|
});
|
|
140
147
|
}
|
|
141
148
|
return payload.collection;
|
|
@@ -149,12 +156,20 @@ class CollectionsService {
|
|
|
149
156
|
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
150
157
|
await (0, cache_1.clearSystemCache)();
|
|
151
158
|
}
|
|
159
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
160
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
161
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
162
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
163
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
152
166
|
}
|
|
153
167
|
}
|
|
154
168
|
/**
|
|
155
169
|
* Create multiple new collections
|
|
156
170
|
*/
|
|
157
171
|
async createMany(payloads, opts) {
|
|
172
|
+
const nestedActionEvents = [];
|
|
158
173
|
try {
|
|
159
174
|
const collections = await this.knex.transaction(async (trx) => {
|
|
160
175
|
const service = new CollectionsService({
|
|
@@ -164,7 +179,11 @@ class CollectionsService {
|
|
|
164
179
|
});
|
|
165
180
|
const collectionNames = [];
|
|
166
181
|
for (const payload of payloads) {
|
|
167
|
-
const name = await service.createOne(payload, {
|
|
182
|
+
const name = await service.createOne(payload, {
|
|
183
|
+
autoPurgeCache: false,
|
|
184
|
+
autoPurgeSystemCache: false,
|
|
185
|
+
bypassEmitAction: (params) => nestedActionEvents.push(params),
|
|
186
|
+
});
|
|
168
187
|
collectionNames.push(name);
|
|
169
188
|
}
|
|
170
189
|
return collectionNames;
|
|
@@ -175,7 +194,16 @@ class CollectionsService {
|
|
|
175
194
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
176
195
|
await this.cache.clear();
|
|
177
196
|
}
|
|
178
|
-
|
|
197
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
198
|
+
await (0, cache_1.clearSystemCache)();
|
|
199
|
+
}
|
|
200
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
201
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
202
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
203
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
204
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
179
207
|
}
|
|
180
208
|
}
|
|
181
209
|
/**
|
|
@@ -277,6 +305,7 @@ class CollectionsService {
|
|
|
277
305
|
if (this.accountability && this.accountability.admin !== true) {
|
|
278
306
|
throw new exceptions_1.ForbiddenException();
|
|
279
307
|
}
|
|
308
|
+
const nestedActionEvents = [];
|
|
280
309
|
try {
|
|
281
310
|
const collectionItemsService = new items_1.ItemsService('directus_collections', {
|
|
282
311
|
knex: this.knex,
|
|
@@ -293,10 +322,16 @@ class CollectionsService {
|
|
|
293
322
|
.where({ collection: collectionKey })
|
|
294
323
|
.first());
|
|
295
324
|
if (exists) {
|
|
296
|
-
await collectionItemsService.updateOne(collectionKey, payload.meta,
|
|
325
|
+
await collectionItemsService.updateOne(collectionKey, payload.meta, {
|
|
326
|
+
...opts,
|
|
327
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
328
|
+
});
|
|
297
329
|
}
|
|
298
330
|
else {
|
|
299
|
-
await collectionItemsService.createOne({ ...payload.meta, collection: collectionKey },
|
|
331
|
+
await collectionItemsService.createOne({ ...payload.meta, collection: collectionKey }, {
|
|
332
|
+
...opts,
|
|
333
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
334
|
+
});
|
|
300
335
|
}
|
|
301
336
|
return collectionKey;
|
|
302
337
|
}
|
|
@@ -307,6 +342,13 @@ class CollectionsService {
|
|
|
307
342
|
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
308
343
|
await (0, cache_1.clearSystemCache)();
|
|
309
344
|
}
|
|
345
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
346
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
347
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
348
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
349
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
310
352
|
}
|
|
311
353
|
}
|
|
312
354
|
/**
|
|
@@ -321,6 +363,7 @@ class CollectionsService {
|
|
|
321
363
|
}
|
|
322
364
|
const collectionKey = 'collection';
|
|
323
365
|
const collectionKeys = [];
|
|
366
|
+
const nestedActionEvents = [];
|
|
324
367
|
try {
|
|
325
368
|
await this.knex.transaction(async (trx) => {
|
|
326
369
|
const collectionItemsService = new CollectionsService({
|
|
@@ -334,6 +377,7 @@ class CollectionsService {
|
|
|
334
377
|
await collectionItemsService.updateOne(payload[collectionKey], (0, lodash_1.omit)(payload, collectionKey), {
|
|
335
378
|
autoPurgeCache: false,
|
|
336
379
|
autoPurgeSystemCache: false,
|
|
380
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
337
381
|
});
|
|
338
382
|
collectionKeys.push(payload[collectionKey]);
|
|
339
383
|
}
|
|
@@ -343,7 +387,16 @@ class CollectionsService {
|
|
|
343
387
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
344
388
|
await this.cache.clear();
|
|
345
389
|
}
|
|
346
|
-
|
|
390
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
391
|
+
await (0, cache_1.clearSystemCache)();
|
|
392
|
+
}
|
|
393
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
394
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
395
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
396
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
397
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
347
400
|
}
|
|
348
401
|
return collectionKeys;
|
|
349
402
|
}
|
|
@@ -354,6 +407,7 @@ class CollectionsService {
|
|
|
354
407
|
if (this.accountability && this.accountability.admin !== true) {
|
|
355
408
|
throw new exceptions_1.ForbiddenException();
|
|
356
409
|
}
|
|
410
|
+
const nestedActionEvents = [];
|
|
357
411
|
try {
|
|
358
412
|
await this.knex.transaction(async (trx) => {
|
|
359
413
|
const service = new CollectionsService({
|
|
@@ -362,7 +416,11 @@ class CollectionsService {
|
|
|
362
416
|
knex: trx,
|
|
363
417
|
});
|
|
364
418
|
for (const collectionKey of collectionKeys) {
|
|
365
|
-
await service.updateOne(collectionKey, data, {
|
|
419
|
+
await service.updateOne(collectionKey, data, {
|
|
420
|
+
autoPurgeCache: false,
|
|
421
|
+
autoPurgeSystemCache: false,
|
|
422
|
+
bypassEmitAction: (params) => nestedActionEvents.push(params),
|
|
423
|
+
});
|
|
366
424
|
}
|
|
367
425
|
});
|
|
368
426
|
return collectionKeys;
|
|
@@ -371,7 +429,16 @@ class CollectionsService {
|
|
|
371
429
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
372
430
|
await this.cache.clear();
|
|
373
431
|
}
|
|
374
|
-
|
|
432
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
433
|
+
await (0, cache_1.clearSystemCache)();
|
|
434
|
+
}
|
|
435
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
436
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
437
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
438
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
439
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
375
442
|
}
|
|
376
443
|
}
|
|
377
444
|
/**
|
|
@@ -382,6 +449,7 @@ class CollectionsService {
|
|
|
382
449
|
if (this.accountability && this.accountability.admin !== true) {
|
|
383
450
|
throw new exceptions_1.ForbiddenException();
|
|
384
451
|
}
|
|
452
|
+
const nestedActionEvents = [];
|
|
385
453
|
try {
|
|
386
454
|
const collections = await this.readByQuery();
|
|
387
455
|
const collectionToBeDeleted = collections.find((collection) => collection.collection === collectionKey);
|
|
@@ -401,7 +469,9 @@ class CollectionsService {
|
|
|
401
469
|
accountability: this.accountability,
|
|
402
470
|
schema: this.schema,
|
|
403
471
|
});
|
|
404
|
-
await collectionItemsService.deleteOne(collectionKey
|
|
472
|
+
await collectionItemsService.deleteOne(collectionKey, {
|
|
473
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
474
|
+
});
|
|
405
475
|
}
|
|
406
476
|
if (collectionToBeDeleted.schema) {
|
|
407
477
|
const fieldsService = new fields_1.FieldsService({
|
|
@@ -429,11 +499,19 @@ class CollectionsService {
|
|
|
429
499
|
for (const relation of relations) {
|
|
430
500
|
// Delete related o2m fields that point to current collection
|
|
431
501
|
if (relation.related_collection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field)) {
|
|
432
|
-
await fieldsService.deleteField(relation.related_collection, relation.meta.one_field
|
|
502
|
+
await fieldsService.deleteField(relation.related_collection, relation.meta.one_field, {
|
|
503
|
+
autoPurgeCache: false,
|
|
504
|
+
autoPurgeSystemCache: false,
|
|
505
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
506
|
+
});
|
|
433
507
|
}
|
|
434
508
|
// Delete related m2o fields that point to current collection
|
|
435
509
|
if (relation.related_collection === collectionKey) {
|
|
436
|
-
await fieldsService.deleteField(relation.collection, relation.field
|
|
510
|
+
await fieldsService.deleteField(relation.collection, relation.field, {
|
|
511
|
+
autoPurgeCache: false,
|
|
512
|
+
autoPurgeSystemCache: false,
|
|
513
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
514
|
+
});
|
|
437
515
|
}
|
|
438
516
|
}
|
|
439
517
|
const a2oRelationsThatIncludeThisCollection = this.schema.relations.filter((relation) => {
|
|
@@ -459,6 +537,13 @@ class CollectionsService {
|
|
|
459
537
|
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
460
538
|
await (0, cache_1.clearSystemCache)();
|
|
461
539
|
}
|
|
540
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
541
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
542
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
543
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
544
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
462
547
|
}
|
|
463
548
|
}
|
|
464
549
|
/**
|
|
@@ -468,6 +553,7 @@ class CollectionsService {
|
|
|
468
553
|
if (this.accountability && this.accountability.admin !== true) {
|
|
469
554
|
throw new exceptions_1.ForbiddenException();
|
|
470
555
|
}
|
|
556
|
+
const nestedActionEvents = [];
|
|
471
557
|
try {
|
|
472
558
|
await this.knex.transaction(async (trx) => {
|
|
473
559
|
const service = new CollectionsService({
|
|
@@ -476,7 +562,11 @@ class CollectionsService {
|
|
|
476
562
|
knex: trx,
|
|
477
563
|
});
|
|
478
564
|
for (const collectionKey of collectionKeys) {
|
|
479
|
-
await service.deleteOne(collectionKey, {
|
|
565
|
+
await service.deleteOne(collectionKey, {
|
|
566
|
+
autoPurgeCache: false,
|
|
567
|
+
autoPurgeSystemCache: false,
|
|
568
|
+
bypassEmitAction: (params) => nestedActionEvents.push(params),
|
|
569
|
+
});
|
|
480
570
|
}
|
|
481
571
|
});
|
|
482
572
|
return collectionKeys;
|
|
@@ -485,7 +575,16 @@ class CollectionsService {
|
|
|
485
575
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
486
576
|
await this.cache.clear();
|
|
487
577
|
}
|
|
488
|
-
|
|
578
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
579
|
+
await (0, cache_1.clearSystemCache)();
|
|
580
|
+
}
|
|
581
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
582
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
583
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
584
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
585
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
489
588
|
}
|
|
490
589
|
}
|
|
491
590
|
}
|
|
@@ -6,7 +6,7 @@ import { Column } from 'knex-schema-inspector/dist/types/column';
|
|
|
6
6
|
import { Helpers } from '../database/helpers';
|
|
7
7
|
import { ItemsService } from '../services/items';
|
|
8
8
|
import { PayloadService } from '../services/payload';
|
|
9
|
-
import { AbstractServiceOptions } from '../types';
|
|
9
|
+
import { AbstractServiceOptions, MutationOptions } from '../types';
|
|
10
10
|
export declare class FieldsService {
|
|
11
11
|
knex: Knex;
|
|
12
12
|
helpers: Helpers;
|
|
@@ -26,6 +26,6 @@ export declare class FieldsService {
|
|
|
26
26
|
type: Type | null;
|
|
27
27
|
}, table?: Knex.CreateTableBuilder): Promise<void>;
|
|
28
28
|
updateField(collection: string, field: RawField): Promise<string>;
|
|
29
|
-
deleteField(collection: string, field: string): Promise<void>;
|
|
29
|
+
deleteField(collection: string, field: string, opts?: MutationOptions): Promise<void>;
|
|
30
30
|
addColumnToTable(table: Knex.CreateTableBuilder, field: RawField | Field, alter?: Column | null): void;
|
|
31
31
|
}
|
package/dist/services/fields.js
CHANGED
|
@@ -46,6 +46,7 @@ const get_default_value_1 = __importDefault(require("../utils/get-default-value"
|
|
|
46
46
|
const get_local_type_1 = __importDefault(require("../utils/get-local-type"));
|
|
47
47
|
const relations_1 = require("./relations");
|
|
48
48
|
const constants_3 = require("@directus/shared/constants");
|
|
49
|
+
const get_schema_1 = require("../utils/get-schema");
|
|
49
50
|
class FieldsService {
|
|
50
51
|
constructor(options) {
|
|
51
52
|
this.knex = options.knex || (0, database_1.default)();
|
|
@@ -223,6 +224,7 @@ class FieldsService {
|
|
|
223
224
|
throw new exceptions_1.ForbiddenException();
|
|
224
225
|
}
|
|
225
226
|
const runPostColumnChange = await this.helpers.schema.preColumnChange();
|
|
227
|
+
const nestedActionEvents = [];
|
|
226
228
|
try {
|
|
227
229
|
const exists = field.field in this.schema.collections[collection].fields ||
|
|
228
230
|
(0, lodash_1.isNil)(await this.knex.select('id').from('directus_fields').where({ collection, field: field.field }).first()) === false;
|
|
@@ -265,14 +267,18 @@ class FieldsService {
|
|
|
265
267
|
field: hookAdjustedField.field,
|
|
266
268
|
}, { emitEvents: false });
|
|
267
269
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
nestedActionEvents.push({
|
|
271
|
+
event: 'fields.create',
|
|
272
|
+
meta: {
|
|
273
|
+
payload: hookAdjustedField,
|
|
274
|
+
key: hookAdjustedField.field,
|
|
275
|
+
collection: collection,
|
|
276
|
+
},
|
|
277
|
+
context: {
|
|
278
|
+
database: (0, database_1.default)(),
|
|
279
|
+
schema: this.schema,
|
|
280
|
+
accountability: this.accountability,
|
|
281
|
+
},
|
|
276
282
|
});
|
|
277
283
|
});
|
|
278
284
|
}
|
|
@@ -284,14 +290,20 @@ class FieldsService {
|
|
|
284
290
|
await this.cache.clear();
|
|
285
291
|
}
|
|
286
292
|
await (0, cache_1.clearSystemCache)();
|
|
293
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
294
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
295
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
296
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
297
|
+
}
|
|
287
298
|
}
|
|
288
299
|
}
|
|
289
300
|
async updateField(collection, field) {
|
|
290
|
-
var _a, _b;
|
|
301
|
+
var _a, _b, _c;
|
|
291
302
|
if (this.accountability && this.accountability.admin !== true) {
|
|
292
303
|
throw new exceptions_1.ForbiddenException();
|
|
293
304
|
}
|
|
294
305
|
const runPostColumnChange = await this.helpers.schema.preColumnChange();
|
|
306
|
+
const nestedActionEvents = [];
|
|
295
307
|
try {
|
|
296
308
|
const hookAdjustedField = await emitter_1.default.emitFilter(`fields.update`, field, {
|
|
297
309
|
keys: [field.field],
|
|
@@ -304,10 +316,10 @@ class FieldsService {
|
|
|
304
316
|
const record = field.meta
|
|
305
317
|
? await this.knex.select('id').from('directus_fields').where({ collection, field: field.field }).first()
|
|
306
318
|
: null;
|
|
307
|
-
if (
|
|
308
|
-
(
|
|
309
|
-
|
|
310
|
-
hookAdjustedField.type !== ((_b = this.schema.collections[collection].fields[field.field]) === null || _b === void 0 ? void 0 : _b.type)) {
|
|
319
|
+
if (hookAdjustedField.type &&
|
|
320
|
+
(hookAdjustedField.type === 'alias' ||
|
|
321
|
+
((_a = this.schema.collections[collection].fields[field.field]) === null || _a === void 0 ? void 0 : _a.type) === 'alias') &&
|
|
322
|
+
hookAdjustedField.type !== ((_c = (_b = this.schema.collections[collection].fields[field.field]) === null || _b === void 0 ? void 0 : _b.type) !== null && _c !== void 0 ? _c : 'alias')) {
|
|
311
323
|
throw new exceptions_1.InvalidPayloadException('Alias type cannot be changed');
|
|
312
324
|
}
|
|
313
325
|
if (hookAdjustedField.schema) {
|
|
@@ -341,14 +353,18 @@ class FieldsService {
|
|
|
341
353
|
}, { emitEvents: false });
|
|
342
354
|
}
|
|
343
355
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
356
|
+
nestedActionEvents.push({
|
|
357
|
+
event: 'fields.update',
|
|
358
|
+
meta: {
|
|
359
|
+
payload: hookAdjustedField,
|
|
360
|
+
keys: [hookAdjustedField.field],
|
|
361
|
+
collection: collection,
|
|
362
|
+
},
|
|
363
|
+
context: {
|
|
364
|
+
database: (0, database_1.default)(),
|
|
365
|
+
schema: this.schema,
|
|
366
|
+
accountability: this.accountability,
|
|
367
|
+
},
|
|
352
368
|
});
|
|
353
369
|
return field.field;
|
|
354
370
|
}
|
|
@@ -360,13 +376,19 @@ class FieldsService {
|
|
|
360
376
|
await this.cache.clear();
|
|
361
377
|
}
|
|
362
378
|
await (0, cache_1.clearSystemCache)();
|
|
379
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
380
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
381
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
382
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
383
|
+
}
|
|
363
384
|
}
|
|
364
385
|
}
|
|
365
|
-
async deleteField(collection, field) {
|
|
386
|
+
async deleteField(collection, field, opts) {
|
|
366
387
|
if (this.accountability && this.accountability.admin !== true) {
|
|
367
388
|
throw new exceptions_1.ForbiddenException();
|
|
368
389
|
}
|
|
369
390
|
const runPostColumnChange = await this.helpers.schema.preColumnChange();
|
|
391
|
+
const nestedActionEvents = [];
|
|
370
392
|
try {
|
|
371
393
|
await emitter_1.default.emitFilter('fields.delete', [field], {
|
|
372
394
|
collection: collection,
|
|
@@ -396,12 +418,19 @@ class FieldsService {
|
|
|
396
418
|
const isM2O = relation.collection === collection && relation.field === field;
|
|
397
419
|
// If the current field is a m2o, delete the related o2m if it exists and remove the relationship
|
|
398
420
|
if (isM2O) {
|
|
399
|
-
await relationsService.deleteOne(collection, field
|
|
421
|
+
await relationsService.deleteOne(collection, field, {
|
|
422
|
+
autoPurgeSystemCache: false,
|
|
423
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
424
|
+
});
|
|
400
425
|
if (relation.related_collection &&
|
|
401
426
|
((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field) &&
|
|
402
427
|
relation.related_collection !== collection &&
|
|
403
428
|
relation.meta.one_field !== field) {
|
|
404
|
-
await fieldsService.deleteField(relation.related_collection, relation.meta.one_field
|
|
429
|
+
await fieldsService.deleteField(relation.related_collection, relation.meta.one_field, {
|
|
430
|
+
autoPurgeCache: false,
|
|
431
|
+
autoPurgeSystemCache: false,
|
|
432
|
+
bypassEmitAction: (params) => (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) ? opts.bypassEmitAction(params) : nestedActionEvents.push(params),
|
|
433
|
+
});
|
|
405
434
|
}
|
|
406
435
|
}
|
|
407
436
|
// If the current field is a o2m, just delete the one field config from the relation
|
|
@@ -448,27 +477,46 @@ class FieldsService {
|
|
|
448
477
|
}
|
|
449
478
|
await trx('directus_fields').delete().where({ collection, field });
|
|
450
479
|
});
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
480
|
+
const actionEvent = {
|
|
481
|
+
event: 'fields.delete',
|
|
482
|
+
meta: {
|
|
483
|
+
payload: [field],
|
|
484
|
+
collection: collection,
|
|
485
|
+
},
|
|
486
|
+
context: {
|
|
487
|
+
database: this.knex,
|
|
488
|
+
schema: this.schema,
|
|
489
|
+
accountability: this.accountability,
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
if (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) {
|
|
493
|
+
opts.bypassEmitAction(actionEvent);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
nestedActionEvents.push(actionEvent);
|
|
497
|
+
}
|
|
459
498
|
}
|
|
460
499
|
finally {
|
|
461
500
|
if (runPostColumnChange) {
|
|
462
501
|
await this.helpers.schema.postColumnChange();
|
|
463
502
|
}
|
|
464
|
-
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
503
|
+
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
465
504
|
await this.cache.clear();
|
|
466
505
|
}
|
|
467
|
-
|
|
506
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
507
|
+
await (0, cache_1.clearSystemCache)();
|
|
508
|
+
}
|
|
509
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
510
|
+
const updatedSchema = await (0, get_schema_1.getSchema)({ accountability: this.accountability || undefined });
|
|
511
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
512
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
513
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
468
516
|
}
|
|
469
517
|
}
|
|
470
518
|
addColumnToTable(table, field, alter = null) {
|
|
471
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
519
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
472
520
|
let column;
|
|
473
521
|
// Don't attempt to add a DB column for alias / corrupt fields
|
|
474
522
|
if (field.type === 'alias' || field.type === 'unknown')
|
|
@@ -487,7 +535,7 @@ class FieldsService {
|
|
|
487
535
|
}
|
|
488
536
|
else if (['float', 'decimal'].includes(field.type)) {
|
|
489
537
|
const type = field.type;
|
|
490
|
-
column = table[type](field.field, ((_d = field.schema) === null || _d === void 0 ? void 0 : _d.numeric_precision)
|
|
538
|
+
column = table[type](field.field, (_e = (_d = field.schema) === null || _d === void 0 ? void 0 : _d.numeric_precision) !== null && _e !== void 0 ? _e : 10, (_g = (_f = field.schema) === null || _f === void 0 ? void 0 : _f.numeric_scale) !== null && _g !== void 0 ? _g : 5);
|
|
491
539
|
}
|
|
492
540
|
else if (field.type === 'csv') {
|
|
493
541
|
column = table.string(field.field);
|
|
@@ -510,7 +558,7 @@ class FieldsService {
|
|
|
510
558
|
else {
|
|
511
559
|
throw new exceptions_1.InvalidPayloadException(`Illegal type passed: "${field.type}"`);
|
|
512
560
|
}
|
|
513
|
-
if (((
|
|
561
|
+
if (((_h = field.schema) === null || _h === void 0 ? void 0 : _h.default_value) !== undefined) {
|
|
514
562
|
if (typeof field.schema.default_value === 'string' &&
|
|
515
563
|
(field.schema.default_value.toLowerCase() === 'now()' || field.schema.default_value === 'CURRENT_TIMESTAMP')) {
|
|
516
564
|
column.defaultTo(this.knex.fn.now());
|
|
@@ -525,7 +573,7 @@ class FieldsService {
|
|
|
525
573
|
column.defaultTo(field.schema.default_value);
|
|
526
574
|
}
|
|
527
575
|
}
|
|
528
|
-
if (((
|
|
576
|
+
if (((_j = field.schema) === null || _j === void 0 ? void 0 : _j.is_nullable) === false) {
|
|
529
577
|
if (!alter || alter.is_nullable === true) {
|
|
530
578
|
column.notNullable();
|
|
531
579
|
}
|
|
@@ -535,15 +583,15 @@ class FieldsService {
|
|
|
535
583
|
column.nullable();
|
|
536
584
|
}
|
|
537
585
|
}
|
|
538
|
-
if ((
|
|
586
|
+
if ((_k = field.schema) === null || _k === void 0 ? void 0 : _k.is_primary_key) {
|
|
539
587
|
column.primary().notNullable();
|
|
540
588
|
}
|
|
541
|
-
else if (((
|
|
589
|
+
else if (((_l = field.schema) === null || _l === void 0 ? void 0 : _l.is_unique) === true) {
|
|
542
590
|
if (!alter || alter.is_unique === false) {
|
|
543
591
|
column.unique();
|
|
544
592
|
}
|
|
545
593
|
}
|
|
546
|
-
else if (((
|
|
594
|
+
else if (((_m = field.schema) === null || _m === void 0 ? void 0 : _m.is_unique) === false) {
|
|
547
595
|
if (alter && alter.is_unique === true) {
|
|
548
596
|
table.dropUnique([field.field]);
|
|
549
597
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -8,6 +8,7 @@ const types_1 = require("@directus/shared/types");
|
|
|
8
8
|
const argon2_1 = __importDefault(require("argon2"));
|
|
9
9
|
const graphql_1 = require("graphql");
|
|
10
10
|
const graphql_compose_1 = require("graphql-compose");
|
|
11
|
+
const process_error_1 = __importDefault(require("./utils/process-error"));
|
|
11
12
|
const lodash_1 = require("lodash");
|
|
12
13
|
const ms_1 = __importDefault(require("ms"));
|
|
13
14
|
const cache_1 = require("../../cache");
|
|
@@ -99,7 +100,7 @@ class GraphQLService {
|
|
|
99
100
|
}
|
|
100
101
|
const formattedResult = {
|
|
101
102
|
...result,
|
|
102
|
-
errors: (_a = result.errors) === null || _a === void 0 ? void 0 : _a.map(
|
|
103
|
+
errors: (_a = result.errors) === null || _a === void 0 ? void 0 : _a.map((error) => (0, process_error_1.default)(this.accountability, error)),
|
|
103
104
|
};
|
|
104
105
|
return formattedResult;
|
|
105
106
|
}
|
|
@@ -1322,6 +1323,8 @@ class GraphQLService {
|
|
|
1322
1323
|
for (const subSelection of selection.selectionSet.selections) {
|
|
1323
1324
|
if (subSelection.kind !== 'Field')
|
|
1324
1325
|
continue;
|
|
1326
|
+
if (subSelection.name.value.startsWith('__'))
|
|
1327
|
+
continue;
|
|
1325
1328
|
children.push(`${subSelection.name.value}(${rootField})`);
|
|
1326
1329
|
}
|
|
1327
1330
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { GraphQLError, GraphQLFormattedError } from 'graphql';
|
|
2
|
+
import { Accountability } from '@directus/shared/types';
|
|
3
|
+
declare const processError: (accountability: Accountability | null, error: Readonly<GraphQLError>) => GraphQLFormattedError;
|
|
4
|
+
export default processError;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const logger_1 = __importDefault(require("../../../logger"));
|
|
7
|
+
const processError = (accountability, error) => {
|
|
8
|
+
logger_1.default.error(error);
|
|
9
|
+
if ((accountability === null || accountability === void 0 ? void 0 : accountability.admin) === true) {
|
|
10
|
+
return {
|
|
11
|
+
...error,
|
|
12
|
+
extensions: {
|
|
13
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return {
|
|
19
|
+
message: 'An unexpected error occurred.',
|
|
20
|
+
extensions: {
|
|
21
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
exports.default = processError;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/services/items.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Accountability, PermissionsAction, Query, SchemaOverview } from '@direc
|
|
|
2
2
|
import Keyv from 'keyv';
|
|
3
3
|
import { Knex } from 'knex';
|
|
4
4
|
import { AbstractService, AbstractServiceOptions, Item as AnyItem, MutationOptions, PrimaryKey } from '../types';
|
|
5
|
-
export
|
|
5
|
+
export type QueryOptions = {
|
|
6
6
|
stripNonRequested?: boolean;
|
|
7
7
|
permissionsAction?: PermissionsAction;
|
|
8
8
|
emitEvents?: boolean;
|