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
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const calculate_field_depth_1 = require("../../src/utils/calculate-field-depth");
|
|
4
|
-
test('Calculates basic depth', () => {
|
|
5
|
-
const filter = {
|
|
6
|
-
name: {
|
|
7
|
-
_eq: 'test',
|
|
8
|
-
},
|
|
9
|
-
};
|
|
10
|
-
const result = (0, calculate_field_depth_1.calculateFieldDepth)(filter);
|
|
11
|
-
expect(result).toBe(1);
|
|
12
|
-
});
|
|
13
|
-
test('Calculates relational depth', () => {
|
|
14
|
-
const filter = {
|
|
15
|
-
author: {
|
|
16
|
-
name: {
|
|
17
|
-
_eq: 'test',
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
const result = (0, calculate_field_depth_1.calculateFieldDepth)(filter);
|
|
22
|
-
expect(result).toBe(2);
|
|
23
|
-
});
|
|
24
|
-
test('Ignores _and/_or', () => {
|
|
25
|
-
const filter = {
|
|
26
|
-
_and: [
|
|
27
|
-
{
|
|
28
|
-
_or: [
|
|
29
|
-
{
|
|
30
|
-
author: {
|
|
31
|
-
name: {
|
|
32
|
-
_eq: 'Directus',
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
status: {
|
|
38
|
-
_eq: 'published',
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
category: {
|
|
45
|
-
_eq: 'recipes',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
};
|
|
50
|
-
const result = (0, calculate_field_depth_1.calculateFieldDepth)(filter);
|
|
51
|
-
expect(result).toBe(2);
|
|
52
|
-
});
|
|
53
|
-
test('Skips underscore prefix in tree', () => {
|
|
54
|
-
const deep = {
|
|
55
|
-
translations: {
|
|
56
|
-
_filter: {
|
|
57
|
-
language_id: {
|
|
58
|
-
code: {
|
|
59
|
-
_eq: 'nl-NL',
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
const result = (0, calculate_field_depth_1.calculateFieldDepth)(deep);
|
|
66
|
-
expect(result).toBe(3);
|
|
67
|
-
});
|
|
68
|
-
test('Calculates _sort in deep correctly', () => {
|
|
69
|
-
const deep = {
|
|
70
|
-
articles: {
|
|
71
|
-
_sort: ['sort', 'category.type.sort'],
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
const result = (0, calculate_field_depth_1.calculateFieldDepth)(deep, ['_sort']);
|
|
75
|
-
expect(result).toBe(4);
|
|
76
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const filter_items_1 = require("../../src/utils/filter-items");
|
|
4
|
-
const items = [
|
|
5
|
-
{
|
|
6
|
-
role: '9bc9fea0-f761-4107-bfb7-b3d06c125e98',
|
|
7
|
-
permissions: {},
|
|
8
|
-
validation: null,
|
|
9
|
-
presets: null,
|
|
10
|
-
fields: ['*'],
|
|
11
|
-
system: true,
|
|
12
|
-
collection: 'directus_settings',
|
|
13
|
-
action: 'read',
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
role: '9bc9fea0-f761-4107-bfb7-b3d06c125e98',
|
|
17
|
-
permissions: {
|
|
18
|
-
user: {
|
|
19
|
-
_eq: '$CURRENT_USER',
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
validation: null,
|
|
23
|
-
presets: null,
|
|
24
|
-
fields: ['*'],
|
|
25
|
-
system: true,
|
|
26
|
-
collection: 'directus_presets',
|
|
27
|
-
action: 'delete',
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
describe('filter items', () => {
|
|
31
|
-
test('return items when no filter', () => {
|
|
32
|
-
const result = (0, filter_items_1.filterItems)(items, undefined);
|
|
33
|
-
expect(result).toStrictEqual(items);
|
|
34
|
-
});
|
|
35
|
-
test('return items when empty filter used', () => {
|
|
36
|
-
const result = (0, filter_items_1.filterItems)(items, {});
|
|
37
|
-
expect(result).toStrictEqual(items);
|
|
38
|
-
});
|
|
39
|
-
test('return filtered items when nested empty filter used', () => {
|
|
40
|
-
const result = (0, filter_items_1.filterItems)(items, {
|
|
41
|
-
_and: [
|
|
42
|
-
{
|
|
43
|
-
action: {
|
|
44
|
-
_eq: 'read',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
{},
|
|
48
|
-
],
|
|
49
|
-
});
|
|
50
|
-
expect(result).toStrictEqual(items.filter((item) => item.action === 'read'));
|
|
51
|
-
});
|
|
52
|
-
test('return filtered items', () => {
|
|
53
|
-
const result = (0, filter_items_1.filterItems)(items, {
|
|
54
|
-
action: {
|
|
55
|
-
_eq: 'read',
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
expect(result).toStrictEqual(items.filter((item) => item.action === 'read'));
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
let factoryEnv = {};
|
|
4
|
-
jest.mock('../../src/env', () => new Proxy({}, {
|
|
5
|
-
get(target, prop) {
|
|
6
|
-
return factoryEnv[prop];
|
|
7
|
-
},
|
|
8
|
-
}));
|
|
9
|
-
const get_auth_providers_1 = require("../../src/utils/get-auth-providers");
|
|
10
|
-
const scenarios = [
|
|
11
|
-
{
|
|
12
|
-
name: 'when no providers configured',
|
|
13
|
-
input: {},
|
|
14
|
-
output: [],
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
name: 'when no driver configured',
|
|
18
|
-
input: {
|
|
19
|
-
AUTH_PROVIDERS: 'directus',
|
|
20
|
-
},
|
|
21
|
-
output: [],
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: 'when single provider and driver are properly configured',
|
|
25
|
-
input: {
|
|
26
|
-
AUTH_PROVIDERS: 'directus',
|
|
27
|
-
AUTH_DIRECTUS_DRIVER: 'openid',
|
|
28
|
-
AUTH_DIRECTUS_LABEL: 'Directus',
|
|
29
|
-
AUTH_DIRECTUS_ICON: 'hare',
|
|
30
|
-
},
|
|
31
|
-
output: [
|
|
32
|
-
{
|
|
33
|
-
name: 'directus',
|
|
34
|
-
driver: 'openid',
|
|
35
|
-
label: 'Directus',
|
|
36
|
-
icon: 'hare',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
name: 'when multiple provider and driver are properly configured',
|
|
42
|
-
input: {
|
|
43
|
-
AUTH_PROVIDERS: 'directus,custom',
|
|
44
|
-
AUTH_DIRECTUS_DRIVER: 'openid',
|
|
45
|
-
AUTH_DIRECTUS_LABEL: 'Directus',
|
|
46
|
-
AUTH_DIRECTUS_ICON: 'hare',
|
|
47
|
-
AUTH_CUSTOM_DRIVER: 'openid',
|
|
48
|
-
AUTH_CUSTOM_ICON: 'lock',
|
|
49
|
-
},
|
|
50
|
-
output: [
|
|
51
|
-
{
|
|
52
|
-
name: 'directus',
|
|
53
|
-
driver: 'openid',
|
|
54
|
-
label: 'Directus',
|
|
55
|
-
icon: 'hare',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: 'custom',
|
|
59
|
-
driver: 'openid',
|
|
60
|
-
icon: 'lock',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
describe('get auth providers', () => {
|
|
66
|
-
for (const scenario of scenarios) {
|
|
67
|
-
test(scenario.name, () => {
|
|
68
|
-
factoryEnv = scenario.input;
|
|
69
|
-
expect((0, get_auth_providers_1.getAuthProviders)()).toEqual(scenario.output);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
});
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get_cache_key_1 = require("../../src/utils/get-cache-key");
|
|
4
|
-
const restUrl = 'http://localhost/items/example';
|
|
5
|
-
const graphQlUrl = 'http://localhost/graphql';
|
|
6
|
-
const accountability = { user: '00000000-0000-0000-0000-000000000000' };
|
|
7
|
-
const method = 'GET';
|
|
8
|
-
const requests = [
|
|
9
|
-
{
|
|
10
|
-
name: 'as unauthenticated request',
|
|
11
|
-
params: { method, originalUrl: restUrl },
|
|
12
|
-
key: '17da8272c9a0ec6eea38a37d6d78bddeb7c79045',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
name: 'as authenticated request',
|
|
16
|
-
params: { method, originalUrl: restUrl, accountability },
|
|
17
|
-
key: '99a6394222a3d7d149ac1662fc2fff506932db58',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: 'a request with a fields query',
|
|
21
|
-
params: { method, originalUrl: restUrl, sanitizedQuery: { fields: ['id', 'name'] } },
|
|
22
|
-
key: 'aa6e2d8a78de4dfb4af6eaa230d1cd9b7d31ed19',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: 'a request with a filter query',
|
|
26
|
-
params: { method, originalUrl: restUrl, sanitizedQuery: { filter: { name: { _eq: 'test' } } } },
|
|
27
|
-
key: 'd7eb8970f0429e1cf85e12eb5bb8669f618b09d3',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'a GraphQL GET query request',
|
|
31
|
-
params: { method, originalUrl: graphQlUrl, query: { query: 'query { test { id } }' } },
|
|
32
|
-
key: '201731b75c627c60554512d819b6935b54c73814',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: 'a GraphQL POST query request',
|
|
36
|
-
params: { method: 'POST', originalUrl: graphQlUrl, body: { query: 'query { test { name } }' } },
|
|
37
|
-
key: '64eb0c48ea69d0863ff930398f29b5c7884f88f7',
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: 'an authenticated GraphQL GET query request',
|
|
41
|
-
params: { method, originalUrl: graphQlUrl, accountability, query: { query: 'query { test { id } }' } },
|
|
42
|
-
key: '9bc52c98dcf2de04c64589f52e0ada1e38d53a90',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'an authenticated GraphQL POST query request',
|
|
46
|
-
params: { method: 'POST', originalUrl: graphQlUrl, accountability, body: { query: 'query { test { name } }' } },
|
|
47
|
-
key: '051ea77ce5ba71bbc88bcb567b9ddc602b585c13',
|
|
48
|
-
},
|
|
49
|
-
];
|
|
50
|
-
const cases = requests.map(({ name, params, key }) => [name, params, key]);
|
|
51
|
-
describe('get cache key', () => {
|
|
52
|
-
test.each(cases)('should create a cache key for %s', (_, params, key) => {
|
|
53
|
-
expect((0, get_cache_key_1.getCacheKey)(params)).toEqual(key);
|
|
54
|
-
});
|
|
55
|
-
test('should create a unique key for each request', () => {
|
|
56
|
-
const keys = cases.map(([, params]) => (0, get_cache_key_1.getCacheKey)(params));
|
|
57
|
-
const hasDuplicate = keys.some((key) => keys.indexOf(key) !== keys.lastIndexOf(key));
|
|
58
|
-
expect(hasDuplicate).toBeFalsy();
|
|
59
|
-
});
|
|
60
|
-
test('should create a unique key for GraphQL requests with different variables', () => {
|
|
61
|
-
const query = 'query Test ($name: String) { test (filter: { name: { _eq: $name } }) { id } }';
|
|
62
|
-
const operationName = 'test';
|
|
63
|
-
const variables1 = JSON.stringify({ name: 'test 1' });
|
|
64
|
-
const variables2 = JSON.stringify({ name: 'test 2' });
|
|
65
|
-
const req1 = { method, originalUrl: graphQlUrl, query: { query, operationName, variables: variables1 } };
|
|
66
|
-
const req2 = { method, originalUrl: graphQlUrl, query: { query, operationName, variables: variables2 } };
|
|
67
|
-
const postReq1 = { method: 'POST', originalUrl: req1.originalUrl, body: req1.query };
|
|
68
|
-
const postReq2 = { method: 'POST', originalUrl: req2.originalUrl, body: req2.query };
|
|
69
|
-
expect((0, get_cache_key_1.getCacheKey)(req1)).not.toEqual((0, get_cache_key_1.getCacheKey)(req2));
|
|
70
|
-
expect((0, get_cache_key_1.getCacheKey)(postReq1)).not.toEqual((0, get_cache_key_1.getCacheKey)(postReq2));
|
|
71
|
-
expect((0, get_cache_key_1.getCacheKey)(req1)).toEqual((0, get_cache_key_1.getCacheKey)(postReq1));
|
|
72
|
-
expect((0, get_cache_key_1.getCacheKey)(req2)).toEqual((0, get_cache_key_1.getCacheKey)(postReq2));
|
|
73
|
-
});
|
|
74
|
-
});
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get_column_path_1 = require("../../src/utils/get-column-path");
|
|
4
|
-
const exceptions_1 = require("../../src/exceptions");
|
|
5
|
-
/*
|
|
6
|
-
{
|
|
7
|
-
path: [ 'author', 'role', 'name' ],
|
|
8
|
-
collection: 'articles',
|
|
9
|
-
aliasMap: {
|
|
10
|
-
author: { role: { name: 'ljnsv' } },
|
|
11
|
-
ljnsv: { role: { name: 'grenv' } }
|
|
12
|
-
},
|
|
13
|
-
relations: []
|
|
14
|
-
|
|
15
|
-
grenv.name
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
path: [ 'author', 'first_name' ],
|
|
19
|
-
collection: 'articles',
|
|
20
|
-
aliasMap: { author: { first_name: 'rnmxt' } },
|
|
21
|
-
relations: []
|
|
22
|
-
|
|
23
|
-
rnmxt.first_name
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
path: [ 'item:headings', 'text' ],
|
|
27
|
-
collection: 'pages_sections',
|
|
28
|
-
aliasMap: { 'item:headings': { text: 'yllus' } },
|
|
29
|
-
relations: [
|
|
30
|
-
*/
|
|
31
|
-
test('Throws an error when the field path is not known in relations', () => {
|
|
32
|
-
const input = {
|
|
33
|
-
path: ['author', 'first_name'],
|
|
34
|
-
collection: 'articles',
|
|
35
|
-
aliasMap: { author: { first_name: 'bjoyu' } },
|
|
36
|
-
relations: [],
|
|
37
|
-
};
|
|
38
|
-
expect(() => (0, get_column_path_1.getColumnPath)(input)).toThrowError(exceptions_1.InvalidQueryException);
|
|
39
|
-
});
|
|
40
|
-
test('Throws an error when an a2o is used without a collection scope', () => {
|
|
41
|
-
const input = {
|
|
42
|
-
path: ['item', 'type'],
|
|
43
|
-
collection: 'pages',
|
|
44
|
-
aliasMap: {},
|
|
45
|
-
relations: [
|
|
46
|
-
{
|
|
47
|
-
collection: 'pages',
|
|
48
|
-
field: 'item',
|
|
49
|
-
related_collection: null,
|
|
50
|
-
meta: {
|
|
51
|
-
one_collection_field: 'collection',
|
|
52
|
-
one_allowed_collections: ['paragraphs', 'headings'],
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
};
|
|
57
|
-
expect(() => (0, get_column_path_1.getColumnPath)(input)).toThrowError(exceptions_1.InvalidQueryException);
|
|
58
|
-
});
|
|
59
|
-
test('Extracts path scope and returns correct alias for a2o', () => {
|
|
60
|
-
const input = {
|
|
61
|
-
path: ['item:headings', 'text'],
|
|
62
|
-
collection: 'pages',
|
|
63
|
-
aliasMap: { 'item:headings': { text: 'abcdef' } },
|
|
64
|
-
relations: [
|
|
65
|
-
{
|
|
66
|
-
collection: 'pages',
|
|
67
|
-
field: 'item',
|
|
68
|
-
related_collection: null,
|
|
69
|
-
meta: {
|
|
70
|
-
one_collection_field: 'collection',
|
|
71
|
-
one_allowed_collections: ['paragraphs', 'headings'],
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
};
|
|
76
|
-
const result = (0, get_column_path_1.getColumnPath)(input);
|
|
77
|
-
expect(result.columnPath).toBe('abcdef.text');
|
|
78
|
-
expect(result.targetCollection).toBe('headings');
|
|
79
|
-
});
|
|
80
|
-
test('Returns correct alias for m2o', () => {
|
|
81
|
-
const input = {
|
|
82
|
-
path: ['author', 'role', 'name'],
|
|
83
|
-
collection: 'articles',
|
|
84
|
-
aliasMap: {
|
|
85
|
-
author: { role: { name: 'ljnsv' } },
|
|
86
|
-
ljnsv: { role: { name: 'grenv' } },
|
|
87
|
-
},
|
|
88
|
-
relations: [
|
|
89
|
-
{
|
|
90
|
-
collection: 'articles',
|
|
91
|
-
field: 'author',
|
|
92
|
-
related_collection: 'directus_users',
|
|
93
|
-
meta: null,
|
|
94
|
-
schema: null,
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
collection: 'directus_users',
|
|
98
|
-
field: 'role',
|
|
99
|
-
related_collection: 'directus_roles',
|
|
100
|
-
meta: null,
|
|
101
|
-
schema: null,
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
};
|
|
105
|
-
const result = (0, get_column_path_1.getColumnPath)(input);
|
|
106
|
-
expect(result.columnPath).toBe('grenv.name');
|
|
107
|
-
expect(result.targetCollection).toBe('directus_roles');
|
|
108
|
-
});
|
|
109
|
-
test('Returns correct alias for o2m (& uses the table name if no alias exists)', () => {
|
|
110
|
-
const input = {
|
|
111
|
-
path: ['categories', 'category_id', 'name'],
|
|
112
|
-
collection: 'articles',
|
|
113
|
-
aliasMap: {},
|
|
114
|
-
relations: [
|
|
115
|
-
{
|
|
116
|
-
collection: 'categories_articles',
|
|
117
|
-
field: 'category_id',
|
|
118
|
-
related_collection: 'categories',
|
|
119
|
-
meta: null,
|
|
120
|
-
schema: null,
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
collection: 'categories_articles',
|
|
124
|
-
field: 'article_id',
|
|
125
|
-
related_collection: 'articles',
|
|
126
|
-
meta: {
|
|
127
|
-
one_field: 'categories',
|
|
128
|
-
},
|
|
129
|
-
schema: null,
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
};
|
|
133
|
-
const result = (0, get_column_path_1.getColumnPath)(input);
|
|
134
|
-
expect(result.columnPath).toBe('categories.name');
|
|
135
|
-
expect(result.targetCollection).toBe('categories');
|
|
136
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get_config_from_env_1 = require("../../src/utils/get-config-from-env");
|
|
4
|
-
jest.mock('../../src/env', () => ({
|
|
5
|
-
OBJECT_BRAND__COLOR: 'purple',
|
|
6
|
-
OBJECT_BRAND__HEX: '#6644FF',
|
|
7
|
-
CAMELCASE_OBJECT__FIRST_KEY: 'firstValue',
|
|
8
|
-
CAMELCASE_OBJECT__SECOND_KEY: 'secondValue',
|
|
9
|
-
}));
|
|
10
|
-
describe('get config from env', () => {
|
|
11
|
-
test('Keys with double underscore should be an object', () => {
|
|
12
|
-
expect((0, get_config_from_env_1.getConfigFromEnv)('OBJECT_')).toStrictEqual({ brand: { color: 'purple', hex: '#6644FF' } });
|
|
13
|
-
});
|
|
14
|
-
test('Keys with double underscore should be an object with camelCase keys', () => {
|
|
15
|
-
expect((0, get_config_from_env_1.getConfigFromEnv)('CAMELCASE_')).toStrictEqual({
|
|
16
|
-
object: { firstKey: 'firstValue', secondKey: 'secondValue' },
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get_relation_info_1 = require("../../src/utils/get-relation-info");
|
|
4
|
-
describe('getRelationInfo', () => {
|
|
5
|
-
it('Errors on suspiciously long implicit $FOLLOW', () => {
|
|
6
|
-
expect(() => (0, get_relation_info_1.getRelationInfo)([], 'related_test_collection', '$FOLLOW(test_collection, test_field, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)')).toThrowError(Error);
|
|
7
|
-
});
|
|
8
|
-
it('Generates a new relation object for an implicit o2m relation', () => {
|
|
9
|
-
const result = (0, get_relation_info_1.getRelationInfo)([], 'related_test_collection', '$FOLLOW(test_collection, test_field)');
|
|
10
|
-
expect(result).toEqual({
|
|
11
|
-
relation: {
|
|
12
|
-
collection: 'test_collection',
|
|
13
|
-
field: 'test_field',
|
|
14
|
-
related_collection: 'related_test_collection',
|
|
15
|
-
schema: null,
|
|
16
|
-
meta: null,
|
|
17
|
-
},
|
|
18
|
-
relationType: 'o2m',
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
it('Generates a new relation object for an implicit o2a relation', () => {
|
|
22
|
-
const result = (0, get_relation_info_1.getRelationInfo)([], 'related_test_collection', '$FOLLOW(test_collection, test_field, test_collection_field)');
|
|
23
|
-
expect(result).toEqual({
|
|
24
|
-
relation: {
|
|
25
|
-
collection: 'test_collection',
|
|
26
|
-
field: 'test_field',
|
|
27
|
-
related_collection: 'related_test_collection',
|
|
28
|
-
schema: null,
|
|
29
|
-
meta: {
|
|
30
|
-
one_collection_field: 'test_collection_field',
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
relationType: 'o2a',
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
it('Returns the correct existing relation for the given collection/field', () => {
|
|
37
|
-
const testRelations = [
|
|
38
|
-
// o2m
|
|
39
|
-
{
|
|
40
|
-
collection: 'articles',
|
|
41
|
-
field: 'author_id',
|
|
42
|
-
related_collection: 'authors',
|
|
43
|
-
meta: {
|
|
44
|
-
one_field: 'articles',
|
|
45
|
-
},
|
|
46
|
-
schema: null,
|
|
47
|
-
},
|
|
48
|
-
// m2o
|
|
49
|
-
{
|
|
50
|
-
collection: 'articles',
|
|
51
|
-
field: 'category_id',
|
|
52
|
-
related_collection: 'categories',
|
|
53
|
-
meta: null,
|
|
54
|
-
schema: null,
|
|
55
|
-
},
|
|
56
|
-
// a2o
|
|
57
|
-
{
|
|
58
|
-
collection: 'pages',
|
|
59
|
-
field: 'item',
|
|
60
|
-
related_collection: null,
|
|
61
|
-
meta: {
|
|
62
|
-
one_collection_field: 'collection',
|
|
63
|
-
one_allowed_collections: ['headings', 'paragraphs', 'images'],
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
];
|
|
67
|
-
const o2mResult = (0, get_relation_info_1.getRelationInfo)(testRelations, 'authors', 'articles');
|
|
68
|
-
expect(o2mResult).toEqual({
|
|
69
|
-
relationType: 'o2m',
|
|
70
|
-
relation: testRelations[0],
|
|
71
|
-
});
|
|
72
|
-
const m2oResult = (0, get_relation_info_1.getRelationInfo)(testRelations, 'articles', 'category_id');
|
|
73
|
-
expect(m2oResult).toEqual({
|
|
74
|
-
relationType: 'm2o',
|
|
75
|
-
relation: testRelations[1],
|
|
76
|
-
});
|
|
77
|
-
const a2oResult = (0, get_relation_info_1.getRelationInfo)(testRelations, 'pages', 'item');
|
|
78
|
-
expect(a2oResult).toEqual({
|
|
79
|
-
relationType: 'a2o',
|
|
80
|
-
relation: testRelations[2],
|
|
81
|
-
});
|
|
82
|
-
const noResult = (0, get_relation_info_1.getRelationInfo)(testRelations, 'does not exist', 'wrong field');
|
|
83
|
-
expect(noResult).toEqual({
|
|
84
|
-
relation: null,
|
|
85
|
-
relationType: null,
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get_relation_type_1 = require("../../src/utils/get-relation-type");
|
|
4
|
-
test('Returns null if no relation object is included', () => {
|
|
5
|
-
const result = (0, get_relation_type_1.getRelationType)({ relation: null, collection: null, field: 'test' });
|
|
6
|
-
expect(result).toBe(null);
|
|
7
|
-
});
|
|
8
|
-
test('Returns a2o if relation matches and includes one_collection_field and one_allowed_collection', () => {
|
|
9
|
-
const relation = {
|
|
10
|
-
collection: 'pages',
|
|
11
|
-
field: 'item',
|
|
12
|
-
related_collection: null,
|
|
13
|
-
meta: {
|
|
14
|
-
one_collection_field: 'collection',
|
|
15
|
-
one_allowed_collections: ['paragraphs', 'headings', 'images'],
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
const result = (0, get_relation_type_1.getRelationType)({
|
|
19
|
-
relation,
|
|
20
|
-
collection: 'pages',
|
|
21
|
-
field: 'item',
|
|
22
|
-
});
|
|
23
|
-
expect(result).toBe('a2o');
|
|
24
|
-
});
|
|
25
|
-
test('Returns m2o', () => {
|
|
26
|
-
const relation = {
|
|
27
|
-
collection: 'articles',
|
|
28
|
-
field: 'author',
|
|
29
|
-
related_collection: 'authors',
|
|
30
|
-
};
|
|
31
|
-
const result = (0, get_relation_type_1.getRelationType)({
|
|
32
|
-
relation,
|
|
33
|
-
collection: 'articles',
|
|
34
|
-
field: 'author',
|
|
35
|
-
});
|
|
36
|
-
expect(result).toBe('m2o');
|
|
37
|
-
});
|
|
38
|
-
test('Returns o2m', () => {
|
|
39
|
-
const relation = {
|
|
40
|
-
collection: 'articles',
|
|
41
|
-
field: 'author',
|
|
42
|
-
related_collection: 'authors',
|
|
43
|
-
meta: {
|
|
44
|
-
one_field: 'articles',
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
const result = (0, get_relation_type_1.getRelationType)({
|
|
48
|
-
relation,
|
|
49
|
-
collection: 'authors',
|
|
50
|
-
field: 'articles',
|
|
51
|
-
});
|
|
52
|
-
expect(result).toBe('o2m');
|
|
53
|
-
});
|
|
54
|
-
test('Returns null when field/collection doesnt match the relationship', () => {
|
|
55
|
-
const relation = {
|
|
56
|
-
collection: 'articles',
|
|
57
|
-
field: 'author',
|
|
58
|
-
related_collection: 'authors',
|
|
59
|
-
meta: {
|
|
60
|
-
one_field: 'articles',
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
const result = (0, get_relation_type_1.getRelationType)({
|
|
64
|
-
relation,
|
|
65
|
-
collection: 'unrelated',
|
|
66
|
-
field: 'wrong',
|
|
67
|
-
});
|
|
68
|
-
expect(result).toBe(null);
|
|
69
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get_string_byte_size_1 = require("../../src/utils/get-string-byte-size");
|
|
4
|
-
test('Returns correct byte size for given input string', () => {
|
|
5
|
-
expect((0, get_string_byte_size_1.stringByteSize)('test')).toBe(4);
|
|
6
|
-
expect((0, get_string_byte_size_1.stringByteSize)('๐ก')).toBe(4);
|
|
7
|
-
expect((0, get_string_byte_size_1.stringByteSize)('๐จโ๐งโ๐ฆ')).toBe(18);
|
|
8
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
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 is_directus_jwt_1 = __importDefault(require("../../src/utils/is-directus-jwt"));
|
|
7
|
-
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
-
test('Returns false for non JWT string', () => {
|
|
9
|
-
const result = (0, is_directus_jwt_1.default)('test');
|
|
10
|
-
expect(result).toBe(false);
|
|
11
|
-
});
|
|
12
|
-
test('Returns false for JWTs with text payload', () => {
|
|
13
|
-
const token = jsonwebtoken_1.default.sign('plaintext', 'secret');
|
|
14
|
-
const result = (0, is_directus_jwt_1.default)(token);
|
|
15
|
-
expect(result).toBe(false);
|
|
16
|
-
});
|
|
17
|
-
test(`Returns false if token issuer isn't "directus"`, () => {
|
|
18
|
-
const token = jsonwebtoken_1.default.sign({ payload: 'content' }, 'secret', { issuer: 'rijk' });
|
|
19
|
-
const result = (0, is_directus_jwt_1.default)(token);
|
|
20
|
-
expect(result).toBe(false);
|
|
21
|
-
});
|
|
22
|
-
test(`Returns true if token is valid JWT and issuer is "directus"`, () => {
|
|
23
|
-
const token = jsonwebtoken_1.default.sign({ payload: 'content' }, 'secret', { issuer: 'directus' });
|
|
24
|
-
const result = (0, is_directus_jwt_1.default)(token);
|
|
25
|
-
expect(result).toBe(true);
|
|
26
|
-
});
|
package/dist/utils/jwt.test.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
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 jwt_1 = require("../../src/utils/jwt");
|
|
7
|
-
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
-
const exceptions_1 = require("../../src/exceptions");
|
|
9
|
-
const payload = { role: null, app_access: false, admin_access: false };
|
|
10
|
-
const secret = 'test-secret';
|
|
11
|
-
const options = { issuer: 'directus' };
|
|
12
|
-
test('Returns the payload of a correctly signed token', () => {
|
|
13
|
-
const token = jsonwebtoken_1.default.sign(payload, secret, options);
|
|
14
|
-
const result = (0, jwt_1.verifyAccessJWT)(token, secret);
|
|
15
|
-
expect(result).toEqual(payload);
|
|
16
|
-
});
|
|
17
|
-
test('Throws TokenExpiredException when token used has expired', () => {
|
|
18
|
-
const token = jsonwebtoken_1.default.sign({ ...payload, exp: new Date().getTime() / 1000 - 500 }, secret, options);
|
|
19
|
-
expect(() => (0, jwt_1.verifyAccessJWT)(token, secret)).toThrow(exceptions_1.TokenExpiredException);
|
|
20
|
-
});
|
|
21
|
-
const InvalidTokenCases = {
|
|
22
|
-
'wrong issuer': jsonwebtoken_1.default.sign(payload, secret, { issuer: 'wrong' }),
|
|
23
|
-
'wrong secret': jsonwebtoken_1.default.sign(payload, 'wrong-secret', options),
|
|
24
|
-
'string payload': jsonwebtoken_1.default.sign('illegal payload', secret),
|
|
25
|
-
'missing properties in token payload': jsonwebtoken_1.default.sign({ role: null }, secret, options),
|
|
26
|
-
};
|
|
27
|
-
Object.entries(InvalidTokenCases).forEach(([title, token]) => test(`Throws InvalidTokenError - ${title}`, () => {
|
|
28
|
-
expect(() => (0, jwt_1.verifyAccessJWT)(token, secret)).toThrow(exceptions_1.InvalidTokenException);
|
|
29
|
-
}));
|
|
30
|
-
test(`Throws ServiceUnavailableException for unexpected error from jsonwebtoken`, () => {
|
|
31
|
-
jest.spyOn(jsonwebtoken_1.default, 'verify').mockImplementation(() => {
|
|
32
|
-
throw new Error();
|
|
33
|
-
});
|
|
34
|
-
const token = jsonwebtoken_1.default.sign(payload, secret, options);
|
|
35
|
-
expect(() => (0, jwt_1.verifyAccessJWT)(token, secret)).toThrow(exceptions_1.ServiceUnavailableException);
|
|
36
|
-
});
|