directus 9.21.0 → 9.22.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/app.js +9 -5
- package/dist/app.test.d.ts +1 -0
- package/dist/auth/drivers/openid.js +3 -1
- package/dist/cli/commands/bootstrap/index.js +2 -2
- package/dist/cli/commands/schema/apply.js +0 -2
- package/dist/cli/commands/schema/snapshot.js +0 -2
- package/dist/cli/commands/security/secret.js +2 -2
- package/dist/cli/utils/create-env/env-stub.liquid +3 -3
- package/dist/cli/utils/create-env/index.js +5 -8
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/controllers/assets.js +9 -7
- package/dist/controllers/files.js +2 -1
- package/dist/controllers/utils.js +2 -2
- package/dist/database/helpers/fn/dialects/mssql.js +2 -1
- package/dist/database/helpers/fn/dialects/mysql.js +3 -2
- package/dist/database/helpers/fn/dialects/oracle.js +2 -1
- package/dist/database/helpers/fn/dialects/postgres.js +2 -1
- package/dist/database/helpers/fn/dialects/sqlite.js +2 -1
- package/dist/database/helpers/fn/types.d.ts +1 -0
- package/dist/database/helpers/fn/types.js +5 -4
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/mssql.d.ts +6 -0
- package/dist/database/helpers/schema/dialects/mssql.js +14 -0
- package/dist/database/helpers/schema/dialects/mysql.d.ts +5 -0
- package/dist/database/helpers/schema/dialects/mysql.js +19 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/oracle.js +3 -0
- package/dist/database/helpers/schema/index.d.ts +2 -2
- package/dist/database/helpers/schema/index.js +4 -4
- package/dist/database/helpers/schema/types.d.ts +5 -0
- package/dist/database/helpers/schema/types.js +13 -0
- package/dist/database/index.d.ts +6 -0
- package/dist/database/index.js +20 -1
- package/dist/database/migrations/20211007A-update-presets.js +2 -2
- package/dist/database/migrations/run.js +7 -31
- package/dist/database/run-ast.js +132 -6
- package/dist/database/system-data/fields/index.js +2 -1
- package/dist/env.js +3 -2
- package/dist/exceptions/range-not-satisfiable.d.ts +1 -1
- package/dist/extensions.d.ts +7 -1
- package/dist/extensions.js +41 -15
- package/dist/logger.js +27 -1
- package/dist/middleware/schema.js +1 -1
- package/dist/operations/request/index.d.ts +1 -2
- package/dist/operations/request/index.js +2 -2
- package/dist/services/assets.d.ts +4 -3
- package/dist/services/assets.js +13 -11
- package/dist/services/authentication.js +4 -3
- package/dist/services/authorization.js +1 -1
- package/dist/services/collections.js +7 -7
- package/dist/services/fields.d.ts +3 -2
- package/dist/services/fields.js +40 -20
- package/dist/services/files.d.ts +4 -3
- package/dist/services/files.js +92 -68
- package/dist/services/flows.d.ts +0 -2
- package/dist/services/flows.js +0 -14
- package/dist/services/flows.test.d.ts +1 -0
- package/dist/services/graphql/index.d.ts +5 -1
- package/dist/services/graphql/index.js +29 -31
- package/dist/services/import-export.d.ts +4 -3
- package/dist/services/items.js +7 -1
- package/dist/services/meta.js +2 -2
- package/dist/services/operations.d.ts +0 -2
- package/dist/services/operations.js +0 -12
- package/dist/services/operations.test.d.ts +1 -0
- package/dist/services/permissions.d.ts +0 -5
- package/dist/services/permissions.js +0 -25
- package/dist/services/permissions.test.d.ts +1 -0
- package/dist/services/relations.d.ts +2 -2
- package/dist/services/relations.js +24 -16
- package/dist/services/roles.js +0 -3
- package/dist/services/roles.test.d.ts +1 -0
- package/dist/services/server.js +8 -6
- package/dist/services/shares.js +2 -2
- package/dist/services/specifications.js +12 -1
- package/dist/services/users.js +10 -4
- package/dist/services/webhooks.d.ts +0 -2
- package/dist/services/webhooks.js +0 -10
- package/dist/services/webhooks.test.d.ts +1 -0
- package/dist/storage/get-storage-driver.d.ts +3 -0
- package/dist/storage/get-storage-driver.js +20 -0
- package/dist/storage/get-storage-driver.test.d.ts +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.js +20 -0
- package/dist/storage/index.test.d.ts +1 -0
- package/dist/storage/register-drivers.d.ts +2 -0
- package/dist/storage/register-drivers.js +22 -0
- package/dist/storage/register-drivers.test.d.ts +1 -0
- package/dist/storage/register-locations.d.ts +2 -0
- package/dist/storage/register-locations.js +17 -0
- package/dist/storage/register-locations.test.d.ts +1 -0
- package/dist/utils/apply-query.d.ts +27 -3
- package/dist/utils/apply-query.js +180 -127
- package/dist/utils/apply-snapshot.js +32 -13
- package/dist/utils/dynamic-import.d.ts +1 -0
- package/dist/utils/dynamic-import.js +7 -0
- package/dist/utils/get-collection-from-alias.d.ts +6 -0
- package/dist/utils/get-collection-from-alias.js +15 -0
- package/dist/utils/get-collection-from-alias.test.d.ts +1 -0
- package/dist/utils/get-column-path.d.ts +14 -8
- package/dist/utils/get-column-path.js +24 -7
- package/dist/utils/get-column.d.ts +8 -1
- package/dist/utils/get-column.js +10 -3
- package/dist/utils/get-config-from-env.js +3 -2
- package/dist/utils/get-default-value.d.ts +1 -1
- package/dist/utils/get-schema.d.ts +6 -2
- package/dist/utils/get-schema.js +1 -1
- package/dist/utils/get-snapshot.js +1 -1
- package/dist/utils/parse-image-metadata.d.ts +3 -0
- package/dist/utils/parse-image-metadata.js +73 -0
- package/dist/utils/track.js +2 -2
- package/dist/utils/validate-env.js +3 -2
- package/dist/webhooks.js +2 -2
- package/package.json +18 -22
- package/dist/storage.d.ts +0 -3
- package/dist/storage.js +0 -61
|
@@ -8,7 +8,6 @@ const types_1 = require("@directus/shared/types");
|
|
|
8
8
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
9
9
|
const lodash_1 = require("lodash");
|
|
10
10
|
const ms_1 = __importDefault(require("ms"));
|
|
11
|
-
const nanoid_1 = require("nanoid");
|
|
12
11
|
const perf_hooks_1 = require("perf_hooks");
|
|
13
12
|
const auth_1 = require("../auth");
|
|
14
13
|
const constants_1 = require("../constants");
|
|
@@ -37,6 +36,7 @@ class AuthenticationService {
|
|
|
37
36
|
*/
|
|
38
37
|
async login(providerName = constants_1.DEFAULT_AUTH_PROVIDER, payload, otp) {
|
|
39
38
|
var _a, _b, _c;
|
|
39
|
+
const { nanoid } = await import('nanoid');
|
|
40
40
|
const STALL_TIME = env_1.default.LOGIN_STALL_TIME;
|
|
41
41
|
const timeStart = perf_hooks_1.performance.now();
|
|
42
42
|
const provider = (0, auth_1.getAuthProvider)(providerName);
|
|
@@ -151,7 +151,7 @@ class AuthenticationService {
|
|
|
151
151
|
expiresIn: env_1.default.ACCESS_TOKEN_TTL,
|
|
152
152
|
issuer: 'directus',
|
|
153
153
|
});
|
|
154
|
-
const refreshToken =
|
|
154
|
+
const refreshToken = nanoid(64);
|
|
155
155
|
const refreshTokenExpiration = new Date(Date.now() + (0, ms_1.default)(env_1.default.REFRESH_TOKEN_TTL));
|
|
156
156
|
await this.knex('directus_sessions').insert({
|
|
157
157
|
token: refreshToken,
|
|
@@ -187,6 +187,7 @@ class AuthenticationService {
|
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
189
|
async refresh(refreshToken) {
|
|
190
|
+
const { nanoid } = await import('nanoid');
|
|
190
191
|
if (!refreshToken) {
|
|
191
192
|
throw new exceptions_1.InvalidCredentialsException();
|
|
192
193
|
}
|
|
@@ -280,7 +281,7 @@ class AuthenticationService {
|
|
|
280
281
|
expiresIn: env_1.default.ACCESS_TOKEN_TTL,
|
|
281
282
|
issuer: 'directus',
|
|
282
283
|
});
|
|
283
|
-
const newRefreshToken =
|
|
284
|
+
const newRefreshToken = nanoid(64);
|
|
284
285
|
const refreshTokenExpiration = new Date(Date.now() + (0, ms_1.default)(env_1.default.REFRESH_TOKEN_TTL));
|
|
285
286
|
await this.knex('directus_sessions')
|
|
286
287
|
.update({
|
|
@@ -178,7 +178,7 @@ class AuthorizationService {
|
|
|
178
178
|
(result[relation.collection] || (result[relation.collection] = new Set())).add(relation.field);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
//
|
|
181
|
+
// a2o filter in the form of `item:collection`
|
|
182
182
|
else if (filterKey.includes(':')) {
|
|
183
183
|
const [field, collectionScope] = filterKey.split(':');
|
|
184
184
|
if (collection) {
|
|
@@ -157,7 +157,7 @@ class CollectionsService {
|
|
|
157
157
|
await (0, cache_1.clearSystemCache)();
|
|
158
158
|
}
|
|
159
159
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
160
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
160
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
161
161
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
162
162
|
nestedActionEvent.context.schema = updatedSchema;
|
|
163
163
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -198,7 +198,7 @@ class CollectionsService {
|
|
|
198
198
|
await (0, cache_1.clearSystemCache)();
|
|
199
199
|
}
|
|
200
200
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
201
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
201
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
202
202
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
203
203
|
nestedActionEvent.context.schema = updatedSchema;
|
|
204
204
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -343,7 +343,7 @@ class CollectionsService {
|
|
|
343
343
|
await (0, cache_1.clearSystemCache)();
|
|
344
344
|
}
|
|
345
345
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
346
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
346
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
347
347
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
348
348
|
nestedActionEvent.context.schema = updatedSchema;
|
|
349
349
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -391,7 +391,7 @@ class CollectionsService {
|
|
|
391
391
|
await (0, cache_1.clearSystemCache)();
|
|
392
392
|
}
|
|
393
393
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
394
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
394
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
395
395
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
396
396
|
nestedActionEvent.context.schema = updatedSchema;
|
|
397
397
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -433,7 +433,7 @@ class CollectionsService {
|
|
|
433
433
|
await (0, cache_1.clearSystemCache)();
|
|
434
434
|
}
|
|
435
435
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
436
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
436
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
437
437
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
438
438
|
nestedActionEvent.context.schema = updatedSchema;
|
|
439
439
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -538,7 +538,7 @@ class CollectionsService {
|
|
|
538
538
|
await (0, cache_1.clearSystemCache)();
|
|
539
539
|
}
|
|
540
540
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
541
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
541
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
542
542
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
543
543
|
nestedActionEvent.context.schema = updatedSchema;
|
|
544
544
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -579,7 +579,7 @@ class CollectionsService {
|
|
|
579
579
|
await (0, cache_1.clearSystemCache)();
|
|
580
580
|
}
|
|
581
581
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
582
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
582
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
583
583
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
584
584
|
nestedActionEvent.context.schema = updatedSchema;
|
|
585
585
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
@@ -24,8 +24,9 @@ export declare class FieldsService {
|
|
|
24
24
|
createField(collection: string, field: Partial<Field> & {
|
|
25
25
|
field: string;
|
|
26
26
|
type: Type | null;
|
|
27
|
-
}, table?: Knex.CreateTableBuilder
|
|
28
|
-
|
|
27
|
+
}, table?: Knex.CreateTableBuilder, // allows collection creation to
|
|
28
|
+
opts?: MutationOptions): Promise<void>;
|
|
29
|
+
updateField(collection: string, field: RawField, opts?: MutationOptions): Promise<string>;
|
|
29
30
|
deleteField(collection: string, field: string, opts?: MutationOptions): Promise<void>;
|
|
30
31
|
addColumnToTable(table: Knex.CreateTableBuilder, field: RawField | Field, alter?: Column | null): void;
|
|
31
32
|
}
|
package/dist/services/fields.js
CHANGED
|
@@ -218,8 +218,8 @@ class FieldsService {
|
|
|
218
218
|
};
|
|
219
219
|
return data;
|
|
220
220
|
}
|
|
221
|
-
async createField(collection, field, table // allows collection creation to
|
|
222
|
-
) {
|
|
221
|
+
async createField(collection, field, table, // allows collection creation to
|
|
222
|
+
opts) {
|
|
223
223
|
if (this.accountability && this.accountability.admin !== true) {
|
|
224
224
|
throw new exceptions_1.ForbiddenException();
|
|
225
225
|
}
|
|
@@ -267,7 +267,7 @@ class FieldsService {
|
|
|
267
267
|
field: hookAdjustedField.field,
|
|
268
268
|
}, { emitEvents: false });
|
|
269
269
|
}
|
|
270
|
-
|
|
270
|
+
const actionEvent = {
|
|
271
271
|
event: 'fields.create',
|
|
272
272
|
meta: {
|
|
273
273
|
payload: hookAdjustedField,
|
|
@@ -279,25 +279,35 @@ class FieldsService {
|
|
|
279
279
|
schema: this.schema,
|
|
280
280
|
accountability: this.accountability,
|
|
281
281
|
},
|
|
282
|
-
}
|
|
282
|
+
};
|
|
283
|
+
if (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) {
|
|
284
|
+
opts.bypassEmitAction(actionEvent);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
nestedActionEvents.push(actionEvent);
|
|
288
|
+
}
|
|
283
289
|
});
|
|
284
290
|
}
|
|
285
291
|
finally {
|
|
286
292
|
if (runPostColumnChange) {
|
|
287
293
|
await this.helpers.schema.postColumnChange();
|
|
288
294
|
}
|
|
289
|
-
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
295
|
+
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
290
296
|
await this.cache.clear();
|
|
291
297
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
298
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
299
|
+
await (0, cache_1.clearSystemCache)();
|
|
300
|
+
}
|
|
301
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
302
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
303
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
304
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
305
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
306
|
+
}
|
|
297
307
|
}
|
|
298
308
|
}
|
|
299
309
|
}
|
|
300
|
-
async updateField(collection, field) {
|
|
310
|
+
async updateField(collection, field, opts) {
|
|
301
311
|
var _a, _b, _c;
|
|
302
312
|
if (this.accountability && this.accountability.admin !== true) {
|
|
303
313
|
throw new exceptions_1.ForbiddenException();
|
|
@@ -353,7 +363,7 @@ class FieldsService {
|
|
|
353
363
|
}, { emitEvents: false });
|
|
354
364
|
}
|
|
355
365
|
}
|
|
356
|
-
|
|
366
|
+
const actionEvent = {
|
|
357
367
|
event: 'fields.update',
|
|
358
368
|
meta: {
|
|
359
369
|
payload: hookAdjustedField,
|
|
@@ -365,21 +375,31 @@ class FieldsService {
|
|
|
365
375
|
schema: this.schema,
|
|
366
376
|
accountability: this.accountability,
|
|
367
377
|
},
|
|
368
|
-
}
|
|
378
|
+
};
|
|
379
|
+
if (opts === null || opts === void 0 ? void 0 : opts.bypassEmitAction) {
|
|
380
|
+
opts.bypassEmitAction(actionEvent);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
nestedActionEvents.push(actionEvent);
|
|
384
|
+
}
|
|
369
385
|
return field.field;
|
|
370
386
|
}
|
|
371
387
|
finally {
|
|
372
388
|
if (runPostColumnChange) {
|
|
373
389
|
await this.helpers.schema.postColumnChange();
|
|
374
390
|
}
|
|
375
|
-
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
391
|
+
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
376
392
|
await this.cache.clear();
|
|
377
393
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
394
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.autoPurgeSystemCache) !== false) {
|
|
395
|
+
await (0, cache_1.clearSystemCache)();
|
|
396
|
+
}
|
|
397
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
398
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
399
|
+
for (const nestedActionEvent of nestedActionEvents) {
|
|
400
|
+
nestedActionEvent.context.schema = updatedSchema;
|
|
401
|
+
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
|
402
|
+
}
|
|
383
403
|
}
|
|
384
404
|
}
|
|
385
405
|
}
|
|
@@ -507,7 +527,7 @@ class FieldsService {
|
|
|
507
527
|
await (0, cache_1.clearSystemCache)();
|
|
508
528
|
}
|
|
509
529
|
if ((opts === null || opts === void 0 ? void 0 : opts.emitEvents) !== false && nestedActionEvents.length > 0) {
|
|
510
|
-
const updatedSchema = await (0, get_schema_1.getSchema)(
|
|
530
|
+
const updatedSchema = await (0, get_schema_1.getSchema)();
|
|
511
531
|
for (const nestedActionEvent of nestedActionEvents) {
|
|
512
532
|
nestedActionEvent.context.schema = updatedSchema;
|
|
513
533
|
emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
|
package/dist/services/files.d.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import {
|
|
2
|
+
import type { Readable } from 'node:stream';
|
|
3
|
+
import { AbstractServiceOptions, File, Metadata, MutationOptions, PrimaryKey } from '../types';
|
|
3
4
|
import { ItemsService } from './items';
|
|
4
5
|
export declare class FilesService extends ItemsService {
|
|
5
6
|
constructor(options: AbstractServiceOptions);
|
|
6
7
|
/**
|
|
7
8
|
* Upload a single new file to the configured storage adapter
|
|
8
9
|
*/
|
|
9
|
-
uploadOne(stream:
|
|
10
|
+
uploadOne(stream: Readable, data: Partial<File> & {
|
|
10
11
|
filename_download: string;
|
|
11
12
|
storage: string;
|
|
12
13
|
}, primaryKey?: PrimaryKey, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
13
14
|
/**
|
|
14
15
|
* Extract metadata from a buffer's content
|
|
15
16
|
*/
|
|
16
|
-
getMetadata(
|
|
17
|
+
getMetadata(stream: Readable, allowList?: any): Promise<Metadata>;
|
|
17
18
|
/**
|
|
18
19
|
* Import a single file from an external URL
|
|
19
20
|
*/
|
package/dist/services/files.js
CHANGED
|
@@ -27,26 +27,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.FilesService = void 0;
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
30
|
+
const utils_1 = require("@directus/shared/utils");
|
|
31
|
+
const dns_1 = require("dns");
|
|
32
|
+
const encodeurl_1 = __importDefault(require("encodeurl"));
|
|
33
|
+
const exif_reader_1 = __importDefault(require("exif-reader"));
|
|
34
|
+
const icc_1 = require("icc");
|
|
33
35
|
const lodash_1 = require("lodash");
|
|
34
36
|
const mime_types_1 = require("mime-types");
|
|
37
|
+
const net_1 = __importDefault(require("net"));
|
|
38
|
+
const promises_1 = require("node:stream/promises");
|
|
39
|
+
const os_1 = __importDefault(require("os"));
|
|
35
40
|
const path_1 = __importDefault(require("path"));
|
|
36
41
|
const sharp_1 = __importDefault(require("sharp"));
|
|
37
42
|
const url_1 = __importStar(require("url"));
|
|
38
43
|
const util_1 = require("util");
|
|
39
|
-
const dns_1 = require("dns");
|
|
40
44
|
const emitter_1 = __importDefault(require("../emitter"));
|
|
41
45
|
const env_1 = __importDefault(require("../env"));
|
|
42
46
|
const exceptions_1 = require("../exceptions");
|
|
43
47
|
const logger_1 = __importDefault(require("../logger"));
|
|
44
|
-
const storage_1 =
|
|
45
|
-
const
|
|
48
|
+
const storage_1 = require("../storage");
|
|
49
|
+
const parse_image_metadata_1 = require("../utils/parse-image-metadata");
|
|
46
50
|
const items_1 = require("./items");
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
const encodeurl_1 = __importDefault(require("encodeurl"));
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
50
53
|
const lookupDNS = (0, util_1.promisify)(dns_1.lookup);
|
|
51
54
|
class FilesService extends items_1.ItemsService {
|
|
52
55
|
constructor(options) {
|
|
@@ -57,6 +60,7 @@ class FilesService extends items_1.ItemsService {
|
|
|
57
60
|
*/
|
|
58
61
|
async uploadOne(stream, data, primaryKey, opts) {
|
|
59
62
|
var _a, _b, _c, _d, _e, _f;
|
|
63
|
+
const storage = await (0, storage_1.getStorage)();
|
|
60
64
|
const payload = (0, lodash_1.clone)(data);
|
|
61
65
|
if ('folder' in payload === false) {
|
|
62
66
|
const settings = await this.knex.select('storage_default_folder').from('directus_settings').first();
|
|
@@ -68,9 +72,9 @@ class FilesService extends items_1.ItemsService {
|
|
|
68
72
|
await this.updateOne(primaryKey, payload, { emitEvents: false });
|
|
69
73
|
// If the file you're uploading already exists, we'll consider this upload a replace. In that case, we'll
|
|
70
74
|
// delete the previously saved file and thumbnails to ensure they're generated fresh
|
|
71
|
-
const disk =
|
|
72
|
-
for await (const
|
|
73
|
-
await disk.delete(
|
|
75
|
+
const disk = storage.location(payload.storage);
|
|
76
|
+
for await (const filepath of disk.list(String(primaryKey))) {
|
|
77
|
+
await disk.delete(filepath);
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
else {
|
|
@@ -82,18 +86,18 @@ class FilesService extends items_1.ItemsService {
|
|
|
82
86
|
payload.type = 'application/octet-stream';
|
|
83
87
|
}
|
|
84
88
|
try {
|
|
85
|
-
await
|
|
89
|
+
await storage.location(data.storage).write(payload.filename_disk, stream, payload.type);
|
|
86
90
|
}
|
|
87
91
|
catch (err) {
|
|
88
92
|
logger_1.default.warn(`Couldn't save file ${payload.filename_disk}`);
|
|
89
93
|
logger_1.default.warn(err);
|
|
90
94
|
throw new exceptions_1.ServiceUnavailableException(`Couldn't save file ${payload.filename_disk}`, { service: 'files' });
|
|
91
95
|
}
|
|
92
|
-
const { size } = await
|
|
96
|
+
const { size } = await storage.location(data.storage).stat(payload.filename_disk);
|
|
93
97
|
payload.filesize = size;
|
|
94
98
|
if (['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/tiff'].includes(payload.type)) {
|
|
95
|
-
const
|
|
96
|
-
const { height, width, description, title, tags, metadata } = await this.getMetadata(
|
|
99
|
+
const stream = await storage.location(data.storage).read(payload.filename_disk);
|
|
100
|
+
const { height, width, description, title, tags, metadata } = await this.getMetadata(stream);
|
|
97
101
|
(_a = payload.height) !== null && _a !== void 0 ? _a : (payload.height = height);
|
|
98
102
|
(_b = payload.width) !== null && _b !== void 0 ? _b : (payload.width = width);
|
|
99
103
|
(_c = payload.description) !== null && _c !== void 0 ? _c : (payload.description = description);
|
|
@@ -127,60 +131,79 @@ class FilesService extends items_1.ItemsService {
|
|
|
127
131
|
/**
|
|
128
132
|
* Extract metadata from a buffer's content
|
|
129
133
|
*/
|
|
130
|
-
async getMetadata(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
metadata
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
134
|
+
async getMetadata(stream, allowList = env_1.default.FILE_METADATA_ALLOW_LIST) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
(0, promises_1.pipeline)(stream, (0, sharp_1.default)().metadata(async (err, sharpMetadata) => {
|
|
137
|
+
var _a, _b, _c, _d;
|
|
138
|
+
if (err)
|
|
139
|
+
reject(err);
|
|
140
|
+
const metadata = {};
|
|
141
|
+
if (sharpMetadata.orientation && sharpMetadata.orientation >= 5) {
|
|
142
|
+
metadata.height = sharpMetadata.width;
|
|
143
|
+
metadata.width = sharpMetadata.height;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
metadata.width = sharpMetadata.width;
|
|
147
|
+
metadata.height = sharpMetadata.height;
|
|
148
|
+
}
|
|
149
|
+
// Backward-compatible layout as it used to be with 'exifr'
|
|
150
|
+
const fullMetadata = {};
|
|
151
|
+
if (sharpMetadata.exif) {
|
|
152
|
+
const { image, thumbnail, interoperability, ...rest } = (0, exif_reader_1.default)(sharpMetadata.exif);
|
|
153
|
+
if (image) {
|
|
154
|
+
fullMetadata.ifd0 = image;
|
|
155
|
+
}
|
|
156
|
+
if (thumbnail) {
|
|
157
|
+
fullMetadata.ifd1 = thumbnail;
|
|
158
|
+
}
|
|
159
|
+
if (interoperability) {
|
|
160
|
+
fullMetadata.interop = interoperability;
|
|
161
|
+
}
|
|
162
|
+
Object.assign(fullMetadata, rest);
|
|
163
|
+
}
|
|
164
|
+
if (sharpMetadata.icc) {
|
|
165
|
+
fullMetadata.icc = (0, icc_1.parse)(sharpMetadata.icc);
|
|
166
|
+
}
|
|
167
|
+
if (sharpMetadata.iptc) {
|
|
168
|
+
fullMetadata.iptc = (0, parse_image_metadata_1.parseIptc)(sharpMetadata.iptc);
|
|
169
|
+
}
|
|
170
|
+
if (sharpMetadata.xmp) {
|
|
171
|
+
fullMetadata.xmp = (0, parse_image_metadata_1.parseXmp)(sharpMetadata.xmp);
|
|
172
|
+
}
|
|
173
|
+
if (((_a = fullMetadata === null || fullMetadata === void 0 ? void 0 : fullMetadata.iptc) === null || _a === void 0 ? void 0 : _a.Caption) && typeof fullMetadata.iptc.Caption === 'string') {
|
|
174
|
+
metadata.description = (_b = fullMetadata.iptc) === null || _b === void 0 ? void 0 : _b.Caption;
|
|
175
|
+
}
|
|
176
|
+
if (((_c = fullMetadata === null || fullMetadata === void 0 ? void 0 : fullMetadata.iptc) === null || _c === void 0 ? void 0 : _c.Headline) && typeof fullMetadata.iptc.Headline === 'string') {
|
|
177
|
+
metadata.title = fullMetadata.iptc.Headline;
|
|
178
|
+
}
|
|
179
|
+
if ((_d = fullMetadata === null || fullMetadata === void 0 ? void 0 : fullMetadata.iptc) === null || _d === void 0 ? void 0 : _d.Keywords) {
|
|
180
|
+
metadata.tags = fullMetadata.iptc.Keywords;
|
|
181
|
+
}
|
|
182
|
+
if (allowList === '*' || (allowList === null || allowList === void 0 ? void 0 : allowList[0]) === '*') {
|
|
183
|
+
metadata.metadata = fullMetadata;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
metadata.metadata = (0, lodash_1.pick)(fullMetadata, allowList);
|
|
187
|
+
}
|
|
188
|
+
// Fix (incorrectly parsed?) values starting / ending with spaces,
|
|
189
|
+
// limited to one level and string values only
|
|
190
|
+
for (const section of Object.keys(metadata.metadata)) {
|
|
191
|
+
for (const [key, value] of Object.entries(metadata.metadata[section])) {
|
|
192
|
+
if (typeof value === 'string') {
|
|
193
|
+
metadata.metadata[section][key] = value.trim();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
resolve(metadata);
|
|
198
|
+
}));
|
|
199
|
+
});
|
|
178
200
|
}
|
|
179
201
|
/**
|
|
180
202
|
* Import a single file from an external URL
|
|
181
203
|
*/
|
|
182
204
|
async importOne(importURL, body) {
|
|
183
205
|
var _a, _b, _c;
|
|
206
|
+
const axios = (await import('axios')).default;
|
|
184
207
|
const fileCreatePermissions = (_b = (_a = this.accountability) === null || _a === void 0 ? void 0 : _a.permissions) === null || _b === void 0 ? void 0 : _b.find((permission) => permission.collection === 'directus_files' && permission.action === 'create');
|
|
185
208
|
if (this.accountability && ((_c = this.accountability) === null || _c === void 0 ? void 0 : _c.admin) !== true && !fileCreatePermissions) {
|
|
186
209
|
throw new exceptions_1.ForbiddenException();
|
|
@@ -230,7 +253,7 @@ class FilesService extends items_1.ItemsService {
|
|
|
230
253
|
}
|
|
231
254
|
let fileResponse;
|
|
232
255
|
try {
|
|
233
|
-
fileResponse = await
|
|
256
|
+
fileResponse = await axios.get((0, encodeurl_1.default)(importURL), {
|
|
234
257
|
responseType: 'stream',
|
|
235
258
|
});
|
|
236
259
|
}
|
|
@@ -273,16 +296,17 @@ class FilesService extends items_1.ItemsService {
|
|
|
273
296
|
* Delete multiple files
|
|
274
297
|
*/
|
|
275
298
|
async deleteMany(keys, opts) {
|
|
299
|
+
const storage = await (0, storage_1.getStorage)();
|
|
276
300
|
const files = await super.readMany(keys, { fields: ['id', 'storage'], limit: -1 });
|
|
277
301
|
if (!files) {
|
|
278
302
|
throw new exceptions_1.ForbiddenException();
|
|
279
303
|
}
|
|
280
304
|
await super.deleteMany(keys);
|
|
281
305
|
for (const file of files) {
|
|
282
|
-
const disk =
|
|
306
|
+
const disk = storage.location(file.storage);
|
|
283
307
|
// Delete file + thumbnails
|
|
284
|
-
for await (const
|
|
285
|
-
await disk.delete(
|
|
308
|
+
for await (const filepath of disk.list(file.id)) {
|
|
309
|
+
await disk.delete(filepath);
|
|
286
310
|
}
|
|
287
311
|
}
|
|
288
312
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
package/dist/services/flows.d.ts
CHANGED
|
@@ -5,9 +5,7 @@ export declare class FlowsService extends ItemsService<FlowRaw> {
|
|
|
5
5
|
constructor(options: AbstractServiceOptions);
|
|
6
6
|
createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
7
7
|
createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
8
|
-
updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
9
8
|
updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
10
9
|
updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
11
|
-
deleteOne(key: PrimaryKey, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
12
10
|
deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
13
11
|
}
|
package/dist/services/flows.js
CHANGED
|
@@ -19,12 +19,6 @@ class FlowsService extends items_1.ItemsService {
|
|
|
19
19
|
await flowManager.reload();
|
|
20
20
|
return result;
|
|
21
21
|
}
|
|
22
|
-
async updateOne(key, data, opts) {
|
|
23
|
-
const flowManager = (0, flows_1.getFlowManager)();
|
|
24
|
-
const result = await super.updateOne(key, data, opts);
|
|
25
|
-
await flowManager.reload();
|
|
26
|
-
return result;
|
|
27
|
-
}
|
|
28
22
|
async updateBatch(data, opts) {
|
|
29
23
|
const flowManager = (0, flows_1.getFlowManager)();
|
|
30
24
|
const result = await super.updateBatch(data, opts);
|
|
@@ -37,14 +31,6 @@ class FlowsService extends items_1.ItemsService {
|
|
|
37
31
|
await flowManager.reload();
|
|
38
32
|
return result;
|
|
39
33
|
}
|
|
40
|
-
async deleteOne(key, opts) {
|
|
41
|
-
const flowManager = (0, flows_1.getFlowManager)();
|
|
42
|
-
// this is to prevent foreign key constraint error on directus_operations resolve/reject during cascade deletion
|
|
43
|
-
await this.knex('directus_operations').update({ resolve: null, reject: null }).where('flow', key);
|
|
44
|
-
const result = await super.deleteOne(key, opts);
|
|
45
|
-
await flowManager.reload();
|
|
46
|
-
return result;
|
|
47
|
-
}
|
|
48
34
|
async deleteMany(keys, opts) {
|
|
49
35
|
const flowManager = (0, flows_1.getFlowManager)();
|
|
50
36
|
// this is to prevent foreign key constraint error on directus_operations resolve/reject during cascade deletion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseException } from '@directus/shared/exceptions';
|
|
2
|
-
import { Accountability, Query, SchemaOverview } from '@directus/shared/types';
|
|
2
|
+
import { Accountability, Filter, Query, SchemaOverview } from '@directus/shared/types';
|
|
3
3
|
import { ArgumentNode, FormattedExecutionResult, FragmentDefinitionNode, GraphQLError, GraphQLResolveInfo, GraphQLSchema, SelectionNode } from 'graphql';
|
|
4
4
|
import { ObjectTypeComposer, SchemaComposer } from 'graphql-compose';
|
|
5
5
|
import { Knex } from 'knex';
|
|
@@ -54,6 +54,10 @@ export declare class GraphQLService {
|
|
|
54
54
|
* Resolve the aggregation query based on the requested aggregated fields
|
|
55
55
|
*/
|
|
56
56
|
getAggregateQuery(rawQuery: Query, selections: readonly SelectionNode[]): Query;
|
|
57
|
+
/**
|
|
58
|
+
* Replace functions from GraphQL format to Directus-Filter format
|
|
59
|
+
*/
|
|
60
|
+
replaceFuncs(filter?: Filter | null): null | undefined | Filter;
|
|
57
61
|
/**
|
|
58
62
|
* Convert Directus-Exception into a GraphQL format, so it can be returned by GraphQL properly.
|
|
59
63
|
*/
|