directus 9.14.0 → 9.14.3
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/security/key.d.ts +1 -0
- package/dist/cli/commands/security/key.js +8 -0
- package/dist/cli/commands/security/secret.d.ts +1 -0
- package/dist/cli/commands/security/secret.js +8 -0
- package/dist/cli/index.js +6 -0
- package/dist/controllers/extensions.js +9 -1
- package/dist/database/helpers/fn/dialects/mssql.d.ts +2 -2
- package/dist/database/helpers/fn/dialects/mssql.js +2 -2
- package/dist/database/helpers/fn/dialects/mysql.d.ts +2 -2
- package/dist/database/helpers/fn/dialects/mysql.js +2 -2
- package/dist/database/helpers/fn/dialects/oracle.d.ts +1 -1
- package/dist/database/helpers/fn/dialects/oracle.js +2 -2
- package/dist/database/helpers/fn/dialects/postgres.d.ts +2 -2
- package/dist/database/helpers/fn/dialects/postgres.js +2 -2
- package/dist/database/helpers/fn/dialects/sqlite.d.ts +1 -1
- package/dist/database/helpers/fn/dialects/sqlite.js +2 -2
- package/dist/database/helpers/fn/types.d.ts +3 -2
- package/dist/database/helpers/fn/types.js +11 -8
- package/dist/database/helpers/index.d.ts +3 -3
- package/dist/database/helpers/schema/dialects/sqlite.d.ts +5 -0
- package/dist/database/helpers/schema/dialects/sqlite.js +17 -0
- package/dist/database/helpers/schema/index.d.ts +1 -1
- package/dist/database/helpers/schema/index.js +4 -4
- package/dist/database/helpers/schema/types.d.ts +2 -0
- package/dist/database/helpers/schema/types.js +6 -0
- package/dist/database/run-ast.js +8 -5
- package/dist/logger.d.ts +0 -1
- package/dist/middleware/authenticate.d.ts +0 -1
- package/dist/middleware/cache.js +3 -3
- package/dist/middleware/graphql.js +9 -7
- package/dist/middleware/respond.js +5 -5
- package/dist/operations/request/index.js +1 -1
- package/dist/services/authorization.js +15 -5
- package/dist/services/fields.js +4 -0
- package/dist/services/graphql/index.js +40 -15
- package/dist/services/server.js +13 -2
- package/dist/types/ast.d.ts +11 -4
- package/dist/utils/apply-query.js +5 -13
- package/dist/utils/apply-snapshot.js +41 -17
- package/dist/utils/filter-items.js +3 -6
- package/dist/utils/get-ast-from-query.js +18 -0
- package/dist/utils/get-column-path.d.ts +5 -1
- package/dist/utils/get-column-path.js +3 -1
- package/dist/utils/get-column.d.ts +2 -2
- package/dist/utils/get-column.js +2 -2
- package/dist/utils/get-config-from-env.js +1 -1
- package/dist/utils/merge-permissions.d.ts +0 -1
- package/package.json +231 -226
- package/dist/utils/generate-joi.d.ts +0 -3
- package/dist/utils/generate-joi.js +0 -145
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function generateKey(): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function generateSecret(): Promise<void>;
|
package/dist/cli/index.js
CHANGED
|
@@ -13,6 +13,8 @@ const count_1 = __importDefault(require("./commands/count"));
|
|
|
13
13
|
const install_1 = __importDefault(require("./commands/database/install"));
|
|
14
14
|
const migrate_1 = __importDefault(require("./commands/database/migrate"));
|
|
15
15
|
const init_1 = __importDefault(require("./commands/init"));
|
|
16
|
+
const key_1 = __importDefault(require("./commands/security/key"));
|
|
17
|
+
const secret_1 = __importDefault(require("./commands/security/secret"));
|
|
16
18
|
const create_1 = __importDefault(require("./commands/roles/create"));
|
|
17
19
|
const create_2 = __importDefault(require("./commands/users/create"));
|
|
18
20
|
const passwd_1 = __importDefault(require("./commands/users/passwd"));
|
|
@@ -28,6 +30,10 @@ async function createCli() {
|
|
|
28
30
|
program.version(pkg.version, '-v, --version');
|
|
29
31
|
program.command('start').description('Start the Directus API').action(server_1.startServer);
|
|
30
32
|
program.command('init').description('Create a new Directus Project').action(init_1.default);
|
|
33
|
+
// Security
|
|
34
|
+
const securityCommand = program.command('security');
|
|
35
|
+
securityCommand.command('key:generate').description('Generate the app key').action(key_1.default);
|
|
36
|
+
securityCommand.command('secret:generate').description('Generate the app secret').action(secret_1.default);
|
|
31
37
|
const dbCommand = program.command('database');
|
|
32
38
|
dbCommand.command('install').description('Install the database').action(install_1.default);
|
|
33
39
|
dbCommand
|
|
@@ -9,6 +9,9 @@ const exceptions_1 = require("../exceptions");
|
|
|
9
9
|
const extensions_1 = require("../extensions");
|
|
10
10
|
const respond_1 = require("../middleware/respond");
|
|
11
11
|
const utils_1 = require("@directus/shared/utils");
|
|
12
|
+
const ms_1 = __importDefault(require("ms"));
|
|
13
|
+
const env_1 = __importDefault(require("../env"));
|
|
14
|
+
const get_cache_headers_1 = require("../utils/get-cache-headers");
|
|
12
15
|
const router = (0, express_1.Router)();
|
|
13
16
|
router.get('/:type', (0, async_handler_1.default)(async (req, res, next) => {
|
|
14
17
|
const type = (0, utils_1.depluralize)(req.params.type);
|
|
@@ -33,7 +36,12 @@ router.get('/:type/index.js', (0, async_handler_1.default)(async (req, res) => {
|
|
|
33
36
|
throw new exceptions_1.RouteNotFoundException(req.path);
|
|
34
37
|
}
|
|
35
38
|
res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
|
|
36
|
-
|
|
39
|
+
if (env_1.default.EXTENSIONS_CACHE_TTL) {
|
|
40
|
+
res.setHeader('Cache-Control', (0, get_cache_headers_1.getCacheControlHeader)(req, (0, ms_1.default)(env_1.default.EXTENSIONS_CACHE_TTL)));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
44
|
+
}
|
|
37
45
|
res.setHeader('Vary', 'Origin, Cache-Control');
|
|
38
46
|
res.end(extensionSource);
|
|
39
47
|
}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FnHelper } from '../types';
|
|
1
|
+
import { FnHelper, FnHelperOptions } from '../types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
export declare class FnHelperMSSQL extends FnHelper {
|
|
4
4
|
year(table: string, column: string): Knex.Raw;
|
|
@@ -9,5 +9,5 @@ export declare class FnHelperMSSQL extends FnHelper {
|
|
|
9
9
|
hour(table: string, column: string): Knex.Raw;
|
|
10
10
|
minute(table: string, column: string): Knex.Raw;
|
|
11
11
|
second(table: string, column: string): Knex.Raw;
|
|
12
|
-
count(table: string, column: string): Knex.Raw<any>;
|
|
12
|
+
count(table: string, column: string, options?: FnHelperOptions): Knex.Raw<any>;
|
|
13
13
|
}
|
|
@@ -27,14 +27,14 @@ class FnHelperMSSQL extends types_1.FnHelper {
|
|
|
27
27
|
second(table, column) {
|
|
28
28
|
return this.knex.raw('DATEPART(second, ??.??)', [table, column]);
|
|
29
29
|
}
|
|
30
|
-
count(table, column) {
|
|
30
|
+
count(table, column, options) {
|
|
31
31
|
var _a, _b, _c, _d, _e;
|
|
32
32
|
const type = (_e = (_d = (_c = (_b = (_a = this.schema.collections) === null || _a === void 0 ? void 0 : _a[table]) === null || _b === void 0 ? void 0 : _b.fields) === null || _c === void 0 ? void 0 : _c[column]) === null || _d === void 0 ? void 0 : _d.type) !== null && _e !== void 0 ? _e : 'unknown';
|
|
33
33
|
if (type === 'json') {
|
|
34
34
|
return this.knex.raw(`(SELECT COUNT(*) FROM OPENJSON(??.??, '$'))`, [table, column]);
|
|
35
35
|
}
|
|
36
36
|
if (type === 'alias') {
|
|
37
|
-
return this._relationalCount(table, column);
|
|
37
|
+
return this._relationalCount(table, column, options);
|
|
38
38
|
}
|
|
39
39
|
throw new Error(`Couldn't extract type from ${table}.${column}`);
|
|
40
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FnHelper } from '../types';
|
|
1
|
+
import { FnHelper, FnHelperOptions } from '../types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
export declare class FnHelperMySQL extends FnHelper {
|
|
4
4
|
year(table: string, column: string): Knex.Raw;
|
|
@@ -9,5 +9,5 @@ export declare class FnHelperMySQL extends FnHelper {
|
|
|
9
9
|
hour(table: string, column: string): Knex.Raw;
|
|
10
10
|
minute(table: string, column: string): Knex.Raw;
|
|
11
11
|
second(table: string, column: string): Knex.Raw;
|
|
12
|
-
count(table: string, column: string): Knex.Raw;
|
|
12
|
+
count(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
13
13
|
}
|
|
@@ -27,14 +27,14 @@ class FnHelperMySQL extends types_1.FnHelper {
|
|
|
27
27
|
second(table, column) {
|
|
28
28
|
return this.knex.raw('SECOND(??.??)', [table, column]);
|
|
29
29
|
}
|
|
30
|
-
count(table, column) {
|
|
30
|
+
count(table, column, options) {
|
|
31
31
|
var _a, _b, _c, _d, _e;
|
|
32
32
|
const type = (_e = (_d = (_c = (_b = (_a = this.schema.collections) === null || _a === void 0 ? void 0 : _a[table]) === null || _b === void 0 ? void 0 : _b.fields) === null || _c === void 0 ? void 0 : _c[column]) === null || _d === void 0 ? void 0 : _d.type) !== null && _e !== void 0 ? _e : 'unknown';
|
|
33
33
|
if (type === 'json') {
|
|
34
34
|
return this.knex.raw('JSON_LENGTH(??.??)', [table, column]);
|
|
35
35
|
}
|
|
36
36
|
if (type === 'alias') {
|
|
37
|
-
return this._relationalCount(table, column);
|
|
37
|
+
return this._relationalCount(table, column, options);
|
|
38
38
|
}
|
|
39
39
|
throw new Error(`Couldn't extract type from ${table}.${column}`);
|
|
40
40
|
}
|
|
@@ -9,5 +9,5 @@ export declare class FnHelperOracle extends FnHelper {
|
|
|
9
9
|
hour(table: string, column: string, options: FnHelperOptions): Knex.Raw;
|
|
10
10
|
minute(table: string, column: string, options: FnHelperOptions): Knex.Raw;
|
|
11
11
|
second(table: string, column: string, options: FnHelperOptions): Knex.Raw;
|
|
12
|
-
count(table: string, column: string): Knex.Raw<any>;
|
|
12
|
+
count(table: string, column: string, options?: FnHelperOptions): Knex.Raw<any>;
|
|
13
13
|
}
|
|
@@ -33,14 +33,14 @@ class FnHelperOracle extends types_1.FnHelper {
|
|
|
33
33
|
second(table, column, options) {
|
|
34
34
|
return this.knex.raw(`TO_CHAR(??.??${parseLocaltime(options === null || options === void 0 ? void 0 : options.type)}, 'SS')`, [table, column]);
|
|
35
35
|
}
|
|
36
|
-
count(table, column) {
|
|
36
|
+
count(table, column, options) {
|
|
37
37
|
var _a, _b, _c, _d, _e;
|
|
38
38
|
const type = (_e = (_d = (_c = (_b = (_a = this.schema.collections) === null || _a === void 0 ? void 0 : _a[table]) === null || _b === void 0 ? void 0 : _b.fields) === null || _c === void 0 ? void 0 : _c[column]) === null || _d === void 0 ? void 0 : _d.type) !== null && _e !== void 0 ? _e : 'unknown';
|
|
39
39
|
if (type === 'json') {
|
|
40
40
|
return this.knex.raw("json_value(??.??, '$.size()')", [table, column]);
|
|
41
41
|
}
|
|
42
42
|
if (type === 'alias') {
|
|
43
|
-
return this._relationalCount(table, column);
|
|
43
|
+
return this._relationalCount(table, column, options);
|
|
44
44
|
}
|
|
45
45
|
throw new Error(`Couldn't extract type from ${table}.${column}`);
|
|
46
46
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FnHelper } from '../types';
|
|
1
|
+
import { FnHelper, FnHelperOptions } from '../types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
export declare class FnHelperPostgres extends FnHelper {
|
|
4
4
|
year(table: string, column: string): Knex.Raw;
|
|
@@ -9,5 +9,5 @@ export declare class FnHelperPostgres extends FnHelper {
|
|
|
9
9
|
hour(table: string, column: string): Knex.Raw;
|
|
10
10
|
minute(table: string, column: string): Knex.Raw;
|
|
11
11
|
second(table: string, column: string): Knex.Raw;
|
|
12
|
-
count(table: string, column: string): Knex.Raw;
|
|
12
|
+
count(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
13
13
|
}
|
|
@@ -27,7 +27,7 @@ class FnHelperPostgres extends types_1.FnHelper {
|
|
|
27
27
|
second(table, column) {
|
|
28
28
|
return this.knex.raw('EXTRACT(SECOND FROM ??.??)', [table, column]);
|
|
29
29
|
}
|
|
30
|
-
count(table, column) {
|
|
30
|
+
count(table, column, options) {
|
|
31
31
|
var _a, _b, _c, _d, _e;
|
|
32
32
|
const type = (_e = (_d = (_c = (_b = (_a = this.schema.collections) === null || _a === void 0 ? void 0 : _a[table]) === null || _b === void 0 ? void 0 : _b.fields) === null || _c === void 0 ? void 0 : _c[column]) === null || _d === void 0 ? void 0 : _d.type) !== null && _e !== void 0 ? _e : 'unknown';
|
|
33
33
|
if (type === 'json') {
|
|
@@ -38,7 +38,7 @@ class FnHelperPostgres extends types_1.FnHelper {
|
|
|
38
38
|
]);
|
|
39
39
|
}
|
|
40
40
|
if (type === 'alias') {
|
|
41
|
-
return this._relationalCount(table, column);
|
|
41
|
+
return this._relationalCount(table, column, options);
|
|
42
42
|
}
|
|
43
43
|
throw new Error(`Couldn't extract type from ${table}.${column}`);
|
|
44
44
|
}
|
|
@@ -9,5 +9,5 @@ export declare class FnHelperSQLite extends FnHelper {
|
|
|
9
9
|
hour(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
10
10
|
minute(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
11
11
|
second(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
12
|
-
count(table: string, column: string): Knex.Raw<any>;
|
|
12
|
+
count(table: string, column: string, options?: FnHelperOptions): Knex.Raw<any>;
|
|
13
13
|
}
|
|
@@ -57,14 +57,14 @@ class FnHelperSQLite extends types_1.FnHelper {
|
|
|
57
57
|
column,
|
|
58
58
|
]);
|
|
59
59
|
}
|
|
60
|
-
count(table, column) {
|
|
60
|
+
count(table, column, options) {
|
|
61
61
|
var _a, _b, _c, _d, _e;
|
|
62
62
|
const type = (_e = (_d = (_c = (_b = (_a = this.schema.collections) === null || _a === void 0 ? void 0 : _a[table]) === null || _b === void 0 ? void 0 : _b.fields) === null || _c === void 0 ? void 0 : _c[column]) === null || _d === void 0 ? void 0 : _d.type) !== null && _e !== void 0 ? _e : 'unknown';
|
|
63
63
|
if (type === 'json') {
|
|
64
64
|
return this.knex.raw(`json_array_length(??.??, '$')`, [table, column]);
|
|
65
65
|
}
|
|
66
66
|
if (type === 'alias') {
|
|
67
|
-
return this._relationalCount(table, column);
|
|
67
|
+
return this._relationalCount(table, column, options);
|
|
68
68
|
}
|
|
69
69
|
throw new Error(`Couldn't extract type from ${table}.${column}`);
|
|
70
70
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { SchemaOverview } from '@directus/shared/types';
|
|
1
|
+
import { Query, SchemaOverview } from '@directus/shared/types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
import { DatabaseHelper } from '../types';
|
|
4
4
|
export declare type FnHelperOptions = {
|
|
5
5
|
type?: string;
|
|
6
|
+
query?: Query;
|
|
6
7
|
};
|
|
7
8
|
export declare abstract class FnHelper extends DatabaseHelper {
|
|
8
9
|
protected knex: Knex;
|
|
@@ -17,5 +18,5 @@ export declare abstract class FnHelper extends DatabaseHelper {
|
|
|
17
18
|
abstract minute(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
18
19
|
abstract second(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
19
20
|
abstract count(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
20
|
-
protected _relationalCount(table: string, column: string): Knex.Raw;
|
|
21
|
+
protected _relationalCount(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
21
22
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FnHelper = void 0;
|
|
4
|
+
const apply_query_1 = require("../../../utils/apply-query");
|
|
4
5
|
const types_1 = require("../types");
|
|
5
6
|
class FnHelper extends types_1.DatabaseHelper {
|
|
6
7
|
constructor(knex, schema) {
|
|
@@ -9,19 +10,21 @@ class FnHelper extends types_1.DatabaseHelper {
|
|
|
9
10
|
this.schema = schema;
|
|
10
11
|
this.schema = schema;
|
|
11
12
|
}
|
|
12
|
-
_relationalCount(table, column) {
|
|
13
|
+
_relationalCount(table, column, options) {
|
|
14
|
+
var _a;
|
|
13
15
|
const relation = this.schema.relations.find((relation) => { var _a; return relation.related_collection === table && ((_a = relation === null || relation === void 0 ? void 0 : relation.meta) === null || _a === void 0 ? void 0 : _a.one_field) === column; });
|
|
14
16
|
const currentPrimary = this.schema.collections[table].primary;
|
|
15
17
|
if (!relation) {
|
|
16
18
|
throw new Error(`Field ${table}.${column} isn't a nested relational collection`);
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
let countQuery = this.knex
|
|
21
|
+
.count('*')
|
|
22
|
+
.from(relation.collection)
|
|
23
|
+
.where(relation.field, '=', this.knex.raw(`??.??`, [table, currentPrimary]));
|
|
24
|
+
if ((_a = options === null || options === void 0 ? void 0 : options.query) === null || _a === void 0 ? void 0 : _a.filter) {
|
|
25
|
+
countQuery = (0, apply_query_1.applyFilter)(this.knex, this.schema, countQuery, options.query.filter, relation.collection, false);
|
|
26
|
+
}
|
|
27
|
+
return this.knex.raw('(' + countQuery.toQuery() + ')');
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
exports.FnHelper = FnHelper;
|
|
@@ -6,8 +6,8 @@ import * as geometryHelpers from './geometry';
|
|
|
6
6
|
import * as schemaHelpers from './schema';
|
|
7
7
|
export declare function getHelpers(database: Knex): {
|
|
8
8
|
date: dateHelpers.postgres | dateHelpers.oracle | dateHelpers.mysql | dateHelpers.mssql | dateHelpers.sqlite;
|
|
9
|
-
st: geometryHelpers.
|
|
10
|
-
schema: schemaHelpers.postgres | schemaHelpers.cockroachdb | schemaHelpers.oracle;
|
|
9
|
+
st: geometryHelpers.sqlite | geometryHelpers.postgres | geometryHelpers.mysql | geometryHelpers.oracle | geometryHelpers.mssql | geometryHelpers.redshift;
|
|
10
|
+
schema: schemaHelpers.sqlite | schemaHelpers.postgres | schemaHelpers.cockroachdb | schemaHelpers.oracle;
|
|
11
11
|
};
|
|
12
|
-
export declare function getFunctions(database: Knex, schema: SchemaOverview): fnHelpers.
|
|
12
|
+
export declare function getFunctions(database: Knex, schema: SchemaOverview): fnHelpers.sqlite | fnHelpers.postgres | fnHelpers.mysql | fnHelpers.oracle | fnHelpers.mssql;
|
|
13
13
|
export declare type Helpers = ReturnType<typeof getHelpers>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaHelperSQLite = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class SchemaHelperSQLite extends types_1.SchemaHelper {
|
|
6
|
+
async preColumnDelete() {
|
|
7
|
+
const foreignCheckStatus = (await this.knex.raw('PRAGMA foreign_keys'))[0].foreign_keys === 1;
|
|
8
|
+
if (foreignCheckStatus) {
|
|
9
|
+
await this.knex.raw('PRAGMA foreign_keys = OFF');
|
|
10
|
+
}
|
|
11
|
+
return foreignCheckStatus;
|
|
12
|
+
}
|
|
13
|
+
async postColumnDelete() {
|
|
14
|
+
await this.knex.raw('PRAGMA foreign_keys = ON');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.SchemaHelperSQLite = SchemaHelperSQLite;
|
|
@@ -2,6 +2,6 @@ export { SchemaHelperDefault as postgres } from './dialects/default';
|
|
|
2
2
|
export { SchemaHelperCockroachDb as cockroachdb } from './dialects/cockroachdb';
|
|
3
3
|
export { SchemaHelperDefault as redshift } from './dialects/default';
|
|
4
4
|
export { SchemaHelperOracle as oracle } from './dialects/oracle';
|
|
5
|
-
export {
|
|
5
|
+
export { SchemaHelperSQLite as sqlite } from './dialects/sqlite';
|
|
6
6
|
export { SchemaHelperDefault as mysql } from './dialects/default';
|
|
7
7
|
export { SchemaHelperDefault as mssql } from './dialects/default';
|
|
@@ -9,9 +9,9 @@ var default_2 = require("./dialects/default");
|
|
|
9
9
|
Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return default_2.SchemaHelperDefault; } });
|
|
10
10
|
var oracle_1 = require("./dialects/oracle");
|
|
11
11
|
Object.defineProperty(exports, "oracle", { enumerable: true, get: function () { return oracle_1.SchemaHelperOracle; } });
|
|
12
|
+
var sqlite_1 = require("./dialects/sqlite");
|
|
13
|
+
Object.defineProperty(exports, "sqlite", { enumerable: true, get: function () { return sqlite_1.SchemaHelperSQLite; } });
|
|
12
14
|
var default_3 = require("./dialects/default");
|
|
13
|
-
Object.defineProperty(exports, "
|
|
15
|
+
Object.defineProperty(exports, "mysql", { enumerable: true, get: function () { return default_3.SchemaHelperDefault; } });
|
|
14
16
|
var default_4 = require("./dialects/default");
|
|
15
|
-
Object.defineProperty(exports, "
|
|
16
|
-
var default_5 = require("./dialects/default");
|
|
17
|
-
Object.defineProperty(exports, "mssql", { enumerable: true, get: function () { return default_5.SchemaHelperDefault; } });
|
|
17
|
+
Object.defineProperty(exports, "mssql", { enumerable: true, get: function () { return default_4.SchemaHelperDefault; } });
|
|
@@ -21,5 +21,7 @@ export declare abstract class SchemaHelper extends DatabaseHelper {
|
|
|
21
21
|
nullable?: boolean;
|
|
22
22
|
default?: any;
|
|
23
23
|
}>(table: string, column: string, options: Options, cb: (builder: Knex.CreateTableBuilder, column: string, options: Options) => Knex.ColumnBuilder): Promise<void>;
|
|
24
|
+
preColumnDelete(): Promise<boolean>;
|
|
25
|
+
postColumnDelete(): Promise<void>;
|
|
24
26
|
}
|
|
25
27
|
export {};
|
|
@@ -85,5 +85,11 @@ class SchemaHelper extends types_1.DatabaseHelper {
|
|
|
85
85
|
await this.changeNullable(table, column, options.nullable);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
async preColumnDelete() {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
async postColumnDelete() {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
exports.SchemaHelper = SchemaHelper;
|
package/dist/database/run-ast.js
CHANGED
|
@@ -92,7 +92,7 @@ async function parseCurrentLevel(schema, collection, children, query) {
|
|
|
92
92
|
const columnsToSelectInternal = [];
|
|
93
93
|
const nestedCollectionNodes = [];
|
|
94
94
|
for (const child of children) {
|
|
95
|
-
if (child.type === 'field') {
|
|
95
|
+
if (child.type === 'field' || child.type === 'functionField') {
|
|
96
96
|
const fieldName = (0, strip_function_1.stripFunction)(child.name);
|
|
97
97
|
if (columnsInCollection.includes(fieldName)) {
|
|
98
98
|
columnsToSelectInternal.push(child.fieldKey);
|
|
@@ -121,7 +121,7 @@ async function parseCurrentLevel(schema, collection, children, query) {
|
|
|
121
121
|
const columnsToSelect = [...new Set(columnsToSelectInternal)];
|
|
122
122
|
const fieldNodes = columnsToSelect.map((column) => {
|
|
123
123
|
var _a;
|
|
124
|
-
return (_a = children.find((childNode) => childNode.type === 'field' && childNode.fieldKey === column)) !== null && _a !== void 0 ? _a : {
|
|
124
|
+
return (_a = children.find((childNode) => (childNode.type === 'field' || childNode.type === 'functionField') && childNode.fieldKey === column)) !== null && _a !== void 0 ? _a : {
|
|
125
125
|
type: 'field',
|
|
126
126
|
name: column,
|
|
127
127
|
fieldKey: column,
|
|
@@ -138,7 +138,7 @@ function getColumnPreprocessor(knex, schema, table) {
|
|
|
138
138
|
alias = fieldNode.fieldKey;
|
|
139
139
|
}
|
|
140
140
|
let field;
|
|
141
|
-
if (fieldNode.type === 'field') {
|
|
141
|
+
if (fieldNode.type === 'field' || fieldNode.type === 'functionField') {
|
|
142
142
|
field = schema.collections[table].fields[(0, strip_function_1.stripFunction)(fieldNode.name)];
|
|
143
143
|
}
|
|
144
144
|
else {
|
|
@@ -147,6 +147,9 @@ function getColumnPreprocessor(knex, schema, table) {
|
|
|
147
147
|
if ((_a = field === null || field === void 0 ? void 0 : field.type) === null || _a === void 0 ? void 0 : _a.startsWith('geometry')) {
|
|
148
148
|
return helpers.st.asText(table, field.field);
|
|
149
149
|
}
|
|
150
|
+
if (fieldNode.type === 'functionField') {
|
|
151
|
+
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema, fieldNode.query);
|
|
152
|
+
}
|
|
150
153
|
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema);
|
|
151
154
|
};
|
|
152
155
|
}
|
|
@@ -299,7 +302,7 @@ function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem
|
|
|
299
302
|
if (!nestedCollectionNodes[relatedCollection])
|
|
300
303
|
nestedCollectionNodes[relatedCollection] = [];
|
|
301
304
|
for (const child of ast.children[relatedCollection]) {
|
|
302
|
-
if (child.type === 'field') {
|
|
305
|
+
if (child.type === 'field' || child.type === 'functionField') {
|
|
303
306
|
fields[relatedCollection].push(child.name);
|
|
304
307
|
}
|
|
305
308
|
else {
|
|
@@ -325,7 +328,7 @@ function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem
|
|
|
325
328
|
const nestedCollectionNodes = [];
|
|
326
329
|
for (const child of ast.children) {
|
|
327
330
|
fields.push(child.fieldKey);
|
|
328
|
-
if (child.type !== 'field') {
|
|
331
|
+
if (child.type !== 'field' && child.type !== 'functionField') {
|
|
329
332
|
nestedCollectionNodes.push(child);
|
|
330
333
|
}
|
|
331
334
|
}
|
package/dist/logger.d.ts
CHANGED
package/dist/middleware/cache.js
CHANGED
|
@@ -10,15 +10,15 @@ const get_cache_headers_1 = require("../utils/get-cache-headers");
|
|
|
10
10
|
const get_cache_key_1 = require("../utils/get-cache-key");
|
|
11
11
|
const logger_1 = __importDefault(require("../logger"));
|
|
12
12
|
const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next) => {
|
|
13
|
-
var _a, _b;
|
|
13
|
+
var _a, _b, _c;
|
|
14
14
|
const { cache } = (0, cache_1.getCache)();
|
|
15
|
-
if (req.method.toLowerCase() !== 'get')
|
|
15
|
+
if (req.method.toLowerCase() !== 'get' && ((_a = req.path) === null || _a === void 0 ? void 0 : _a.startsWith('/graphql')) === false)
|
|
16
16
|
return next();
|
|
17
17
|
if (env_1.default.CACHE_ENABLED !== true)
|
|
18
18
|
return next();
|
|
19
19
|
if (!cache)
|
|
20
20
|
return next();
|
|
21
|
-
if (((
|
|
21
|
+
if (((_b = req.headers['cache-control']) === null || _b === void 0 ? void 0 : _b.includes('no-store')) || ((_c = req.headers['Cache-Control']) === null || _c === void 0 ? void 0 : _c.includes('no-store'))) {
|
|
22
22
|
if (env_1.default.CACHE_STATUS_HEADER)
|
|
23
23
|
res.setHeader(`${env_1.default.CACHE_STATUS_HEADER}`, 'MISS');
|
|
24
24
|
return next();
|
|
@@ -47,14 +47,16 @@ exports.parseGraphQL = (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
47
47
|
graphqlErrors: [err],
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
+
const operationAST = (0, graphql_1.getOperationAST)(document, operationName);
|
|
50
51
|
// You can only do `query` through GET
|
|
51
|
-
if (req.method === 'GET') {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
if (req.method === 'GET' && (operationAST === null || operationAST === void 0 ? void 0 : operationAST.operation) !== 'query') {
|
|
53
|
+
throw new exceptions_1.MethodNotAllowedException(`Can only perform a ${operationAST === null || operationAST === void 0 ? void 0 : operationAST.operation} from a POST request.`, {
|
|
54
|
+
allow: ['POST'],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Prevent caching responses when mutations are made
|
|
58
|
+
if ((operationAST === null || operationAST === void 0 ? void 0 : operationAST.operation) === 'mutation') {
|
|
59
|
+
res.locals.cache = false;
|
|
58
60
|
}
|
|
59
61
|
res.locals.graphqlParams = { document, query, variables, operationName, contextValue: { req, res } };
|
|
60
62
|
return next();
|
|
@@ -16,7 +16,7 @@ const get_date_formatted_1 = require("../utils/get-date-formatted");
|
|
|
16
16
|
const get_string_byte_size_1 = require("../utils/get-string-byte-size");
|
|
17
17
|
const bytes_1 = require("bytes");
|
|
18
18
|
exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
19
|
-
var _a, _b, _c;
|
|
19
|
+
var _a, _b, _c, _d;
|
|
20
20
|
const { cache } = (0, cache_1.getCache)();
|
|
21
21
|
let exceedsMaxSize = false;
|
|
22
22
|
if (env_1.default.CACHE_VALUE_MAX_SIZE !== false) {
|
|
@@ -24,7 +24,7 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
|
24
24
|
const maxSize = (0, bytes_1.parse)(env_1.default.CACHE_VALUE_MAX_SIZE);
|
|
25
25
|
exceedsMaxSize = valueSize > maxSize;
|
|
26
26
|
}
|
|
27
|
-
if (req.method.toLowerCase() === 'get' &&
|
|
27
|
+
if ((req.method.toLowerCase() === 'get' || ((_a = req.path) === null || _a === void 0 ? void 0 : _a.startsWith('/graphql'))) &&
|
|
28
28
|
env_1.default.CACHE_ENABLED === true &&
|
|
29
29
|
cache &&
|
|
30
30
|
!req.sanitizedQuery.export &&
|
|
@@ -59,17 +59,17 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
|
59
59
|
if (req.sanitizedQuery.export === 'json') {
|
|
60
60
|
res.attachment(`${filename}.json`);
|
|
61
61
|
res.set('Content-Type', 'application/json');
|
|
62
|
-
return res.status(200).send(exportService.transform((
|
|
62
|
+
return res.status(200).send(exportService.transform((_b = res.locals.payload) === null || _b === void 0 ? void 0 : _b.data, 'json'));
|
|
63
63
|
}
|
|
64
64
|
if (req.sanitizedQuery.export === 'xml') {
|
|
65
65
|
res.attachment(`${filename}.xml`);
|
|
66
66
|
res.set('Content-Type', 'text/xml');
|
|
67
|
-
return res.status(200).send(exportService.transform((
|
|
67
|
+
return res.status(200).send(exportService.transform((_c = res.locals.payload) === null || _c === void 0 ? void 0 : _c.data, 'xml'));
|
|
68
68
|
}
|
|
69
69
|
if (req.sanitizedQuery.export === 'csv') {
|
|
70
70
|
res.attachment(`${filename}.csv`);
|
|
71
71
|
res.set('Content-Type', 'text/csv');
|
|
72
|
-
return res.status(200).send(exportService.transform((
|
|
72
|
+
return res.status(200).send(exportService.transform((_d = res.locals.payload) === null || _d === void 0 ? void 0 : _d.data, 'csv'));
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
if (Buffer.isBuffer(res.locals.payload)) {
|
|
@@ -12,7 +12,7 @@ exports.default = (0, utils_1.defineOperationApi)({
|
|
|
12
12
|
acc[header] = value;
|
|
13
13
|
return acc;
|
|
14
14
|
}, {});
|
|
15
|
-
const result = await (0, axios_1.default)({ url, method, data: body, headers: customHeaders });
|
|
15
|
+
const result = await (0, axios_1.default)({ url: encodeURI(url), method, data: body, headers: customHeaders });
|
|
16
16
|
return { status: result.status, statusText: result.statusText, headers: result.headers, data: result.data };
|
|
17
17
|
},
|
|
18
18
|
});
|
|
@@ -48,7 +48,7 @@ class AuthorizationService {
|
|
|
48
48
|
collections.push(...ast.names.map((name) => ({ collection: name, field: ast.fieldKey })));
|
|
49
49
|
for (const children of Object.values(ast.children)) {
|
|
50
50
|
for (const nestedNode of children) {
|
|
51
|
-
if (nestedNode.type !== 'field') {
|
|
51
|
+
if (nestedNode.type !== 'field' && nestedNode.type !== 'functionField') {
|
|
52
52
|
collections.push(...getCollectionsFromAST(nestedNode));
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -60,7 +60,13 @@ class AuthorizationService {
|
|
|
60
60
|
field: ast.type === 'root' ? null : ast.fieldKey,
|
|
61
61
|
});
|
|
62
62
|
for (const nestedNode of ast.children) {
|
|
63
|
-
if (nestedNode.type
|
|
63
|
+
if (nestedNode.type === 'functionField') {
|
|
64
|
+
collections.push({
|
|
65
|
+
collection: nestedNode.relatedCollection,
|
|
66
|
+
field: null,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else if (nestedNode.type !== 'field') {
|
|
64
70
|
collections.push(...getCollectionsFromAST(nestedNode));
|
|
65
71
|
}
|
|
66
72
|
}
|
|
@@ -69,7 +75,7 @@ class AuthorizationService {
|
|
|
69
75
|
}
|
|
70
76
|
function validateFields(ast) {
|
|
71
77
|
var _a, _b, _c;
|
|
72
|
-
if (ast.type !== 'field') {
|
|
78
|
+
if (ast.type !== 'field' && ast.type !== 'functionField') {
|
|
73
79
|
if (ast.type === 'a2o') {
|
|
74
80
|
for (const [collection, children] of Object.entries(ast.children)) {
|
|
75
81
|
checkFields(collection, children, (_b = (_a = ast.query) === null || _a === void 0 ? void 0 : _a[collection]) === null || _b === void 0 ? void 0 : _b.aggregate);
|
|
@@ -112,7 +118,7 @@ class AuthorizationService {
|
|
|
112
118
|
function validateFilterPermissions(ast, schema, action, accountability) {
|
|
113
119
|
var _a, _b, _c, _d, _e;
|
|
114
120
|
let requiredFieldPermissions = {};
|
|
115
|
-
if (ast.type !== 'field') {
|
|
121
|
+
if (ast.type !== 'field' && ast.type !== 'functionField') {
|
|
116
122
|
if (ast.type === 'a2o') {
|
|
117
123
|
for (const collection of Object.keys(ast.children)) {
|
|
118
124
|
requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, extractRequiredFieldPermissions(collection, (_c = (_b = (_a = ast.query) === null || _a === void 0 ? void 0 : _a[collection]) === null || _b === void 0 ? void 0 : _b.filter) !== null && _c !== void 0 ? _c : {}));
|
|
@@ -290,7 +296,11 @@ class AuthorizationService {
|
|
|
290
296
|
}
|
|
291
297
|
}
|
|
292
298
|
function applyFilters(ast, accountability) {
|
|
293
|
-
if (ast.type
|
|
299
|
+
if (ast.type === 'functionField') {
|
|
300
|
+
const collection = ast.relatedCollection;
|
|
301
|
+
updateFilterQuery(collection, ast.query);
|
|
302
|
+
}
|
|
303
|
+
else if (ast.type !== 'field') {
|
|
294
304
|
if (ast.type === 'a2o') {
|
|
295
305
|
const collections = Object.keys(ast.children);
|
|
296
306
|
for (const collection of collections) {
|
package/dist/services/fields.js
CHANGED
|
@@ -351,6 +351,7 @@ class FieldsService {
|
|
|
351
351
|
if (this.accountability && this.accountability.admin !== true) {
|
|
352
352
|
throw new exceptions_1.ForbiddenException();
|
|
353
353
|
}
|
|
354
|
+
const runPostColumnDelete = await this.helpers.schema.preColumnDelete();
|
|
354
355
|
try {
|
|
355
356
|
await emitter_1.default.emitFilter('fields.delete', [field], {
|
|
356
357
|
collection: collection,
|
|
@@ -439,6 +440,9 @@ class FieldsService {
|
|
|
439
440
|
});
|
|
440
441
|
}
|
|
441
442
|
finally {
|
|
443
|
+
if (runPostColumnDelete) {
|
|
444
|
+
await this.helpers.schema.postColumnDelete();
|
|
445
|
+
}
|
|
442
446
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
443
447
|
await this.cache.clear();
|
|
444
448
|
}
|