directus 9.18.1 → 9.19.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/commands/roles/create.js +1 -1
- package/dist/cli/utils/create-env/env-stub.liquid +3 -2
- package/dist/controllers/collections.js +18 -0
- package/dist/database/run-ast.js +11 -4
- package/dist/database/system-data/fields/activity.yaml +2 -1
- package/dist/database/system-data/fields/collections.yaml +8 -4
- package/dist/database/system-data/fields/dashboards.yaml +6 -3
- package/dist/database/system-data/fields/fields.yaml +18 -9
- package/dist/database/system-data/fields/files.yaml +14 -7
- package/dist/database/system-data/fields/flows.yaml +10 -5
- package/dist/database/system-data/fields/folders.yaml +2 -1
- package/dist/database/system-data/fields/operations.yaml +8 -4
- package/dist/database/system-data/fields/panels.yaml +8 -4
- package/dist/database/system-data/fields/permissions.yaml +8 -4
- package/dist/database/system-data/fields/presets.yaml +10 -5
- package/dist/database/system-data/fields/relations.yaml +2 -1
- package/dist/database/system-data/fields/revisions.yaml +4 -2
- package/dist/database/system-data/fields/roles.yaml +12 -6
- package/dist/database/system-data/fields/settings.yaml +10 -5
- package/dist/database/system-data/fields/shares.yaml +7 -3
- package/dist/database/system-data/fields/users.yaml +15 -7
- package/dist/database/system-data/fields/webhooks.yaml +8 -4
- package/dist/env.js +4 -2
- package/dist/env.test.js +1 -0
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +10 -3
- package/dist/messenger.d.ts +3 -3
- package/dist/services/collections.d.ts +4 -0
- package/dist/services/collections.js +50 -5
- package/dist/services/graphql/index.js +80 -65
- package/dist/services/graphql/types/date.d.ts +1 -1
- package/dist/services/graphql/types/geojson.d.ts +1 -1
- package/dist/services/graphql/types/hash.d.ts +1 -1
- package/dist/services/graphql/types/string-or-float.d.ts +1 -1
- package/dist/services/graphql/types/void.d.ts +1 -1
- package/dist/services/mail/templates/base.liquid +0 -1
- package/dist/services/payload.js +2 -2
- package/dist/services/payload.test.js +102 -0
- package/dist/types/items.d.ts +4 -0
- package/dist/utils/apply-query.js +10 -2
- package/dist/utils/get-ast-from-query.js +1 -1
- package/dist/utils/get-auth-providers.d.ts +1 -0
- package/dist/utils/get-auth-providers.js +1 -0
- package/dist/utils/get-auth-providers.test.d.ts +1 -0
- package/dist/utils/get-auth-providers.test.js +72 -0
- package/dist/utils/get-relation-info.js +10 -4
- package/package.json +121 -122
|
@@ -20,7 +20,9 @@ fields:
|
|
|
20
20
|
width: half
|
|
21
21
|
|
|
22
22
|
- field: password
|
|
23
|
-
special:
|
|
23
|
+
special:
|
|
24
|
+
- hash
|
|
25
|
+
- conceal
|
|
24
26
|
interface: input-hash
|
|
25
27
|
options:
|
|
26
28
|
iconRight: lock
|
|
@@ -50,7 +52,8 @@ fields:
|
|
|
50
52
|
|
|
51
53
|
- field: tags
|
|
52
54
|
interface: tags
|
|
53
|
-
special:
|
|
55
|
+
special:
|
|
56
|
+
- cast-json
|
|
54
57
|
width: full
|
|
55
58
|
options:
|
|
56
59
|
iconRight: local_offer
|
|
@@ -89,13 +92,15 @@ fields:
|
|
|
89
92
|
|
|
90
93
|
- field: tfa_secret
|
|
91
94
|
interface: system-mfa-setup
|
|
92
|
-
special:
|
|
95
|
+
special:
|
|
96
|
+
- conceal
|
|
93
97
|
width: half
|
|
94
98
|
|
|
95
99
|
- field: email_notifications
|
|
96
100
|
interface: boolean
|
|
97
101
|
width: half
|
|
98
|
-
special:
|
|
102
|
+
special:
|
|
103
|
+
- cast-boolean
|
|
99
104
|
|
|
100
105
|
- field: admin_divider
|
|
101
106
|
interface: presentation-divider
|
|
@@ -128,7 +133,8 @@ fields:
|
|
|
128
133
|
interface: select-dropdown-m2o
|
|
129
134
|
options:
|
|
130
135
|
template: '{{ name }}'
|
|
131
|
-
special:
|
|
136
|
+
special:
|
|
137
|
+
- m2o
|
|
132
138
|
width: half
|
|
133
139
|
display: related-values
|
|
134
140
|
display_options:
|
|
@@ -136,11 +142,13 @@ fields:
|
|
|
136
142
|
|
|
137
143
|
- field: token
|
|
138
144
|
interface: system-token
|
|
139
|
-
special:
|
|
145
|
+
special:
|
|
146
|
+
- conceal
|
|
140
147
|
width: full
|
|
141
148
|
|
|
142
149
|
- field: id
|
|
143
|
-
special:
|
|
150
|
+
special:
|
|
151
|
+
- uuid
|
|
144
152
|
interface: input
|
|
145
153
|
options:
|
|
146
154
|
iconRight: vpn_key
|
|
@@ -60,12 +60,14 @@ fields:
|
|
|
60
60
|
interface: boolean
|
|
61
61
|
options:
|
|
62
62
|
label: $t:fields.directus_webhooks.data_label
|
|
63
|
-
special:
|
|
63
|
+
special:
|
|
64
|
+
- cast-boolean
|
|
64
65
|
width: half
|
|
65
66
|
display: boolean
|
|
66
67
|
|
|
67
68
|
- field: headers
|
|
68
|
-
special:
|
|
69
|
+
special:
|
|
70
|
+
- cast-json
|
|
69
71
|
interface: list
|
|
70
72
|
options:
|
|
71
73
|
template: '{{ header }}: {{ value }}'
|
|
@@ -105,7 +107,8 @@ fields:
|
|
|
105
107
|
value: update
|
|
106
108
|
- text: $t:delete_label
|
|
107
109
|
value: delete
|
|
108
|
-
special:
|
|
110
|
+
special:
|
|
111
|
+
- cast-csv
|
|
109
112
|
width: full
|
|
110
113
|
display: labels
|
|
111
114
|
display_options:
|
|
@@ -129,7 +132,8 @@ fields:
|
|
|
129
132
|
|
|
130
133
|
- field: collections
|
|
131
134
|
interface: system-collections
|
|
132
|
-
special:
|
|
135
|
+
special:
|
|
136
|
+
- cast-csv
|
|
133
137
|
width: full
|
|
134
138
|
display: labels
|
|
135
139
|
display_options:
|
package/dist/env.js
CHANGED
|
@@ -92,6 +92,7 @@ const allowedEnvironmentVars = [
|
|
|
92
92
|
'STORAGE_.+_ENDPOINT',
|
|
93
93
|
'STORAGE_.+_ACL',
|
|
94
94
|
'STORAGE_.+_CONTAINER_NAME',
|
|
95
|
+
'STORAGE_.+_SERVER_SIDE_ENCRYPTION',
|
|
95
96
|
'STORAGE_.+_ACCOUNT_NAME',
|
|
96
97
|
'STORAGE_.+_ACCOUNT_KEY',
|
|
97
98
|
'STORAGE_.+_ENDPOINT',
|
|
@@ -123,6 +124,7 @@ const allowedEnvironmentVars = [
|
|
|
123
124
|
'AUTH_.+_ALLOW_PUBLIC_REGISTRATION',
|
|
124
125
|
'AUTH_.+_DEFAULT_ROLE_ID',
|
|
125
126
|
'AUTH_.+_ICON',
|
|
127
|
+
'AUTH_.+_LABEL',
|
|
126
128
|
'AUTH_.+_PARAMS',
|
|
127
129
|
'AUTH_.+_ISSUER_URL',
|
|
128
130
|
'AUTH_.+_AUTH_REQUIRE_VERIFIED_EMAIL',
|
|
@@ -186,7 +188,7 @@ const defaults = {
|
|
|
186
188
|
HOST: '0.0.0.0',
|
|
187
189
|
PORT: 8055,
|
|
188
190
|
PUBLIC_URL: '/',
|
|
189
|
-
MAX_PAYLOAD_SIZE: '
|
|
191
|
+
MAX_PAYLOAD_SIZE: '1mb',
|
|
190
192
|
MAX_RELATIONAL_DEPTH: 10,
|
|
191
193
|
DB_EXCLUDE_TABLES: 'spatial_ref_sys,sysdiagrams',
|
|
192
194
|
STORAGE_LOCATIONS: 'local',
|
|
@@ -351,7 +353,7 @@ function processValues(env) {
|
|
|
351
353
|
if (key.length > 5 && key.endsWith('_FILE')) {
|
|
352
354
|
newKey = key.slice(0, -5);
|
|
353
355
|
if (allowedEnvironmentVars.some((pattern) => pattern.test(newKey))) {
|
|
354
|
-
if (newKey in env) {
|
|
356
|
+
if (newKey in env && !(newKey in defaults && env[newKey] === defaults[newKey])) {
|
|
355
357
|
throw new Error(`Duplicate environment variable encountered: you can't use "${newKey}" and "${key}" simultaneously.`);
|
|
356
358
|
}
|
|
357
359
|
try {
|
package/dist/env.test.js
CHANGED
package/dist/logger.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
|
-
import
|
|
3
|
-
declare const logger: pino.Logger
|
|
2
|
+
import { LoggerOptions } from 'pino';
|
|
3
|
+
declare const logger: import("pino").Logger<LoggerOptions & Record<string, any>>;
|
|
4
4
|
export declare const expressLogger: RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
|
|
5
5
|
export default logger;
|
package/dist/logger.js
CHANGED
|
@@ -33,6 +33,7 @@ const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
|
33
33
|
const url_1 = require("url");
|
|
34
34
|
const env_1 = __importDefault(require("./env"));
|
|
35
35
|
const utils_1 = require("@directus/shared/utils");
|
|
36
|
+
const lodash_1 = require("lodash");
|
|
36
37
|
const pinoOptions = {
|
|
37
38
|
level: env_1.default.LOG_LEVEL || 'info',
|
|
38
39
|
redact: {
|
|
@@ -41,8 +42,14 @@ const pinoOptions = {
|
|
|
41
42
|
},
|
|
42
43
|
};
|
|
43
44
|
if (env_1.default.LOG_STYLE !== 'raw') {
|
|
44
|
-
pinoOptions.
|
|
45
|
-
|
|
45
|
+
pinoOptions.transport = {
|
|
46
|
+
target: 'pino-http-print',
|
|
47
|
+
options: {
|
|
48
|
+
all: true,
|
|
49
|
+
translateTime: 'SYS:HH:MM:ss',
|
|
50
|
+
relativeUrl: true,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
46
53
|
}
|
|
47
54
|
const loggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_', 'LOGGER_HTTP');
|
|
48
55
|
// Expose custom log levels into formatter function
|
|
@@ -62,7 +69,7 @@ if (loggerEnvConfig.levels) {
|
|
|
62
69
|
};
|
|
63
70
|
delete loggerEnvConfig.levels;
|
|
64
71
|
}
|
|
65
|
-
const logger = (0, pino_1.default)(
|
|
72
|
+
const logger = (0, pino_1.default)((0, lodash_1.merge)(pinoOptions, loggerEnvConfig));
|
|
66
73
|
const httpLoggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_HTTP', ['LOGGER_HTTP_LOGGER']);
|
|
67
74
|
exports.expressLogger = (0, pino_http_1.default)({
|
|
68
75
|
logger,
|
package/dist/messenger.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { Redis } from 'ioredis';
|
|
2
2
|
export declare type MessengerSubscriptionCallback = (payload: Record<string, any>) => void;
|
|
3
3
|
export interface Messenger {
|
|
4
4
|
publish: (channel: string, payload: Record<string, any>) => void;
|
|
@@ -14,8 +14,8 @@ export declare class MessengerMemory implements Messenger {
|
|
|
14
14
|
}
|
|
15
15
|
export declare class MessengerRedis implements Messenger {
|
|
16
16
|
namespace: string;
|
|
17
|
-
pub:
|
|
18
|
-
sub:
|
|
17
|
+
pub: Redis;
|
|
18
|
+
sub: Redis;
|
|
19
19
|
constructor();
|
|
20
20
|
publish(channel: string, payload: Record<string, any>): void;
|
|
21
21
|
subscribe(channel: string, callback: MessengerSubscriptionCallback): void;
|
|
@@ -44,6 +44,10 @@ export declare class CollectionsService {
|
|
|
44
44
|
* Update a single collection by name
|
|
45
45
|
*/
|
|
46
46
|
updateOne(collectionKey: string, data: Partial<Collection>, opts?: MutationOptions): Promise<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Update multiple collections in a single transaction
|
|
49
|
+
*/
|
|
50
|
+
updateBatch(data: Partial<Collection>[], opts?: MutationOptions): Promise<string[]>;
|
|
47
51
|
/**
|
|
48
52
|
* Update multiple collections by name
|
|
49
53
|
*/
|
|
@@ -38,6 +38,7 @@ const fields_1 = require("../services/fields");
|
|
|
38
38
|
const items_1 = require("../services/items");
|
|
39
39
|
const utils_1 = require("@directus/shared/utils");
|
|
40
40
|
const helpers_1 = require("../database/helpers");
|
|
41
|
+
const lodash_1 = require("lodash");
|
|
41
42
|
class CollectionsService {
|
|
42
43
|
constructor(options) {
|
|
43
44
|
this.knex = options.knex || (0, database_1.default)();
|
|
@@ -145,7 +146,9 @@ class CollectionsService {
|
|
|
145
146
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
146
147
|
await this.cache.clear();
|
|
147
148
|
}
|
|
148
|
-
|
|
149
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
150
|
+
await (0, cache_1.clearSystemCache)();
|
|
151
|
+
}
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
/**
|
|
@@ -161,7 +164,7 @@ class CollectionsService {
|
|
|
161
164
|
});
|
|
162
165
|
const collectionNames = [];
|
|
163
166
|
for (const payload of payloads) {
|
|
164
|
-
const name = await service.createOne(payload, { autoPurgeCache: false });
|
|
167
|
+
const name = await service.createOne(payload, { autoPurgeCache: false, autoPurgeSystemCache: false });
|
|
165
168
|
collectionNames.push(name);
|
|
166
169
|
}
|
|
167
170
|
return collectionNames;
|
|
@@ -297,12 +300,52 @@ class CollectionsService {
|
|
|
297
300
|
}
|
|
298
301
|
return collectionKey;
|
|
299
302
|
}
|
|
303
|
+
finally {
|
|
304
|
+
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
305
|
+
await this.cache.clear();
|
|
306
|
+
}
|
|
307
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
308
|
+
await (0, cache_1.clearSystemCache)();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Update multiple collections in a single transaction
|
|
314
|
+
*/
|
|
315
|
+
async updateBatch(data, opts) {
|
|
316
|
+
if (this.accountability && this.accountability.admin !== true) {
|
|
317
|
+
throw new exceptions_1.ForbiddenException();
|
|
318
|
+
}
|
|
319
|
+
if (!Array.isArray(data)) {
|
|
320
|
+
throw new exceptions_1.InvalidPayloadException('Input should be an array of collection changes.');
|
|
321
|
+
}
|
|
322
|
+
const collectionKey = 'collection';
|
|
323
|
+
const collectionKeys = [];
|
|
324
|
+
try {
|
|
325
|
+
await this.knex.transaction(async (trx) => {
|
|
326
|
+
const collectionItemsService = new CollectionsService({
|
|
327
|
+
knex: trx,
|
|
328
|
+
accountability: this.accountability,
|
|
329
|
+
schema: this.schema,
|
|
330
|
+
});
|
|
331
|
+
for (const payload of data) {
|
|
332
|
+
if (!payload[collectionKey])
|
|
333
|
+
throw new exceptions_1.InvalidPayloadException(`Collection in update misses collection key.`);
|
|
334
|
+
await collectionItemsService.updateOne(payload[collectionKey], (0, lodash_1.omit)(payload, collectionKey), {
|
|
335
|
+
autoPurgeCache: false,
|
|
336
|
+
autoPurgeSystemCache: false,
|
|
337
|
+
});
|
|
338
|
+
collectionKeys.push(payload[collectionKey]);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
300
342
|
finally {
|
|
301
343
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
302
344
|
await this.cache.clear();
|
|
303
345
|
}
|
|
304
346
|
await (0, cache_1.clearSystemCache)();
|
|
305
347
|
}
|
|
348
|
+
return collectionKeys;
|
|
306
349
|
}
|
|
307
350
|
/**
|
|
308
351
|
* Update multiple collections by name
|
|
@@ -319,7 +362,7 @@ class CollectionsService {
|
|
|
319
362
|
knex: trx,
|
|
320
363
|
});
|
|
321
364
|
for (const collectionKey of collectionKeys) {
|
|
322
|
-
await service.updateOne(collectionKey, data, { autoPurgeCache: false });
|
|
365
|
+
await service.updateOne(collectionKey, data, { autoPurgeCache: false, autoPurgeSystemCache: false });
|
|
323
366
|
}
|
|
324
367
|
});
|
|
325
368
|
return collectionKeys;
|
|
@@ -413,7 +456,9 @@ class CollectionsService {
|
|
|
413
456
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
414
457
|
await this.cache.clear();
|
|
415
458
|
}
|
|
416
|
-
|
|
459
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
460
|
+
await (0, cache_1.clearSystemCache)();
|
|
461
|
+
}
|
|
417
462
|
}
|
|
418
463
|
}
|
|
419
464
|
/**
|
|
@@ -431,7 +476,7 @@ class CollectionsService {
|
|
|
431
476
|
knex: trx,
|
|
432
477
|
});
|
|
433
478
|
for (const collectionKey of collectionKeys) {
|
|
434
|
-
await service.deleteOne(collectionKey, { autoPurgeCache: false });
|
|
479
|
+
await service.deleteOne(collectionKey, { autoPurgeCache: false, autoPurgeSystemCache: false });
|
|
435
480
|
}
|
|
436
481
|
});
|
|
437
482
|
return collectionKeys;
|