directus 9.6.0 → 9.7.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 +3 -1
- package/dist/auth/drivers/oauth2.js +3 -0
- package/dist/auth/drivers/openid.js +3 -0
- package/dist/cache.d.ts +4 -1
- package/dist/cache.js +27 -5
- package/dist/cli/commands/schema/apply.d.ts +1 -0
- package/dist/cli/commands/schema/apply.js +9 -5
- package/dist/cli/index.js +1 -0
- package/dist/controllers/assets.js +9 -1
- package/dist/controllers/utils.js +18 -1
- package/dist/database/run-ast.js +7 -1
- package/dist/env.js +5 -2
- package/dist/exceptions/database/dialects/mysql.js +23 -17
- package/dist/middleware/respond.js +7 -28
- package/dist/services/collections.js +6 -6
- package/dist/services/fields.js +3 -3
- package/dist/services/files.js +69 -3
- package/dist/services/graphql.js +2 -2
- package/dist/services/import-export.d.ts +34 -0
- package/dist/services/import-export.js +270 -0
- package/dist/services/index.d.ts +2 -1
- package/dist/services/index.js +2 -1
- package/dist/services/permissions.js +10 -10
- package/dist/services/relations.js +7 -4
- package/dist/utils/get-date-formatted.d.ts +1 -0
- package/dist/utils/get-date-formatted.js +14 -0
- package/dist/utils/get-permissions.js +1 -1
- package/dist/utils/get-schema.js +1 -1
- package/package.json +13 -12
- package/dist/services/import.d.ts +0 -13
- package/dist/services/import.js +0 -118
package/dist/app.js
CHANGED
|
@@ -111,9 +111,11 @@ async function createApp() {
|
|
|
111
111
|
// friendly. Ref #10806
|
|
112
112
|
upgradeInsecureRequests: null,
|
|
113
113
|
// These are required for MapLibre
|
|
114
|
+
// https://cdn.directus.io is required for images/videos in the official docs
|
|
114
115
|
workerSrc: ["'self'", 'blob:'],
|
|
115
116
|
childSrc: ["'self'", 'blob:'],
|
|
116
|
-
imgSrc: ["'self'", 'data:', 'blob:'],
|
|
117
|
+
imgSrc: ["'self'", 'data:', 'blob:', 'https://cdn.directus.io'],
|
|
118
|
+
mediaSrc: ["'self'", 'https://cdn.directus.io'],
|
|
117
119
|
connectSrc: ["'self'", 'https://*'],
|
|
118
120
|
},
|
|
119
121
|
}, (0, get_config_from_env_1.getConfigFromEnv)('CONTENT_SECURITY_POLICY_'))));
|
|
@@ -18,6 +18,7 @@ const async_handler_1 = __importDefault(require("../../utils/async-handler"));
|
|
|
18
18
|
const url_1 = require("../../utils/url");
|
|
19
19
|
const logger_1 = __importDefault(require("../../logger"));
|
|
20
20
|
const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
|
|
21
|
+
const get_config_from_env_1 = require("../../utils/get-config-from-env");
|
|
21
22
|
class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
22
23
|
constructor(options, config) {
|
|
23
24
|
super(options, config);
|
|
@@ -35,11 +36,13 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
35
36
|
userinfo_endpoint: profileUrl,
|
|
36
37
|
issuer: additionalConfig.provider,
|
|
37
38
|
});
|
|
39
|
+
const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_CLIENT_`, [`AUTH_${config.provider.toUpperCase()}_CLIENT_ID`, `AUTH_${config.provider.toUpperCase()}_CLIENT_SECRET`], 'underscore');
|
|
38
40
|
this.client = new issuer.Client({
|
|
39
41
|
client_id: clientId,
|
|
40
42
|
client_secret: clientSecret,
|
|
41
43
|
redirect_uris: [this.redirectUrl],
|
|
42
44
|
response_types: ['code'],
|
|
45
|
+
...clientOptionsOverrides,
|
|
43
46
|
});
|
|
44
47
|
}
|
|
45
48
|
generateCodeVerifier() {
|
|
@@ -18,6 +18,7 @@ const async_handler_1 = __importDefault(require("../../utils/async-handler"));
|
|
|
18
18
|
const url_1 = require("../../utils/url");
|
|
19
19
|
const logger_1 = __importDefault(require("../../logger"));
|
|
20
20
|
const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
|
|
21
|
+
const get_config_from_env_1 = require("../../utils/get-config-from-env");
|
|
21
22
|
class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
22
23
|
constructor(options, config) {
|
|
23
24
|
super(options, config);
|
|
@@ -26,6 +27,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
26
27
|
throw new exceptions_1.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
|
|
27
28
|
}
|
|
28
29
|
const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
|
|
30
|
+
const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_CLIENT_`, [`AUTH_${config.provider.toUpperCase()}_CLIENT_ID`, `AUTH_${config.provider.toUpperCase()}_CLIENT_SECRET`], 'underscore');
|
|
29
31
|
this.redirectUrl = redirectUrl.toString();
|
|
30
32
|
this.usersService = new services_1.UsersService({ knex: this.knex, schema: this.schema });
|
|
31
33
|
this.config = additionalConfig;
|
|
@@ -43,6 +45,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
43
45
|
client_secret: clientSecret,
|
|
44
46
|
redirect_uris: [this.redirectUrl],
|
|
45
47
|
response_types: ['code'],
|
|
48
|
+
...clientOptionsOverrides,
|
|
46
49
|
}));
|
|
47
50
|
})
|
|
48
51
|
.catch(reject);
|
package/dist/cache.d.ts
CHANGED
|
@@ -2,5 +2,8 @@ import Keyv from 'keyv';
|
|
|
2
2
|
export declare function getCache(): {
|
|
3
3
|
cache: Keyv | null;
|
|
4
4
|
systemCache: Keyv;
|
|
5
|
+
lockCache: Keyv;
|
|
5
6
|
};
|
|
6
|
-
export declare function flushCaches(): Promise<void>;
|
|
7
|
+
export declare function flushCaches(forced?: boolean): Promise<void>;
|
|
8
|
+
export declare function clearSystemCache(forced?: boolean): Promise<void>;
|
|
9
|
+
export declare function setSystemCache(key: string, value: any, ttl?: number): Promise<void>;
|
package/dist/cache.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.flushCaches = exports.getCache = void 0;
|
|
6
|
+
exports.setSystemCache = exports.clearSystemCache = exports.flushCaches = exports.getCache = void 0;
|
|
7
7
|
const keyv_1 = __importDefault(require("keyv"));
|
|
8
8
|
const ms_1 = __importDefault(require("ms"));
|
|
9
9
|
const env_1 = __importDefault(require("./env"));
|
|
@@ -12,6 +12,7 @@ const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
|
12
12
|
const validate_env_1 = require("./utils/validate-env");
|
|
13
13
|
let cache = null;
|
|
14
14
|
let systemCache = null;
|
|
15
|
+
let lockCache = null;
|
|
15
16
|
function getCache() {
|
|
16
17
|
if (env_1.default.CACHE_ENABLED === true && cache === null) {
|
|
17
18
|
(0, validate_env_1.validateEnv)(['CACHE_NAMESPACE', 'CACHE_TTL', 'CACHE_STORE']);
|
|
@@ -22,15 +23,36 @@ function getCache() {
|
|
|
22
23
|
systemCache = getKeyvInstance(undefined, '_system');
|
|
23
24
|
systemCache.on('error', (err) => logger_1.default.warn(err, `[cache] ${err}`));
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
+
if (lockCache === null) {
|
|
27
|
+
lockCache = getKeyvInstance(undefined, '_lock');
|
|
28
|
+
lockCache.on('error', (err) => logger_1.default.warn(err, `[cache] ${err}`));
|
|
29
|
+
}
|
|
30
|
+
return { cache, systemCache, lockCache };
|
|
26
31
|
}
|
|
27
32
|
exports.getCache = getCache;
|
|
28
|
-
async function flushCaches() {
|
|
29
|
-
const {
|
|
30
|
-
await (
|
|
33
|
+
async function flushCaches(forced) {
|
|
34
|
+
const { cache } = getCache();
|
|
35
|
+
await clearSystemCache(forced);
|
|
31
36
|
await (cache === null || cache === void 0 ? void 0 : cache.clear());
|
|
32
37
|
}
|
|
33
38
|
exports.flushCaches = flushCaches;
|
|
39
|
+
async function clearSystemCache(forced) {
|
|
40
|
+
const { systemCache, lockCache } = getCache();
|
|
41
|
+
// Flush system cache when forced or when system cache lock not set
|
|
42
|
+
if (forced || !(await lockCache.get('system-cache-lock'))) {
|
|
43
|
+
await lockCache.set('system-cache-lock', true, 10000);
|
|
44
|
+
await systemCache.clear();
|
|
45
|
+
await lockCache.delete('system-cache-lock');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.clearSystemCache = clearSystemCache;
|
|
49
|
+
async function setSystemCache(key, value, ttl) {
|
|
50
|
+
const { systemCache, lockCache } = getCache();
|
|
51
|
+
if (!(await lockCache.get('system-cache-lock'))) {
|
|
52
|
+
await systemCache.set(key, value, ttl);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.setSystemCache = setSystemCache;
|
|
34
56
|
function getKeyvInstance(ttl, namespaceSuffix) {
|
|
35
57
|
switch (env_1.default.CACHE_STORE) {
|
|
36
58
|
case 'redis':
|
|
@@ -63,7 +63,9 @@ async function apply(snapshotPath, options) {
|
|
|
63
63
|
database.destroy();
|
|
64
64
|
process.exit(0);
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
const dryRun = (options === null || options === void 0 ? void 0 : options.dryRun) === true;
|
|
67
|
+
const promptForChanges = !dryRun && (options === null || options === void 0 ? void 0 : options.yes) !== true;
|
|
68
|
+
if (dryRun || promptForChanges) {
|
|
67
69
|
let message = '';
|
|
68
70
|
if (snapshotDiff.collections.length > 0) {
|
|
69
71
|
message += chalk_1.default.black.underline.bold('Collections:');
|
|
@@ -141,14 +143,16 @@ async function apply(snapshotPath, options) {
|
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
}
|
|
146
|
+
message += 'The following changes will be applied:\n\n' + chalk_1.default.black(message);
|
|
147
|
+
if (dryRun) {
|
|
148
|
+
logger_1.default.info(message);
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
144
151
|
const { proceed } = await inquirer_1.default.prompt([
|
|
145
152
|
{
|
|
146
153
|
type: 'confirm',
|
|
147
154
|
name: 'proceed',
|
|
148
|
-
message:
|
|
149
|
-
chalk_1.default.black(message) +
|
|
150
|
-
'\n\n' +
|
|
151
|
-
'Would you like to continue?',
|
|
155
|
+
message: message + '\n\n' + 'Would you like to continue?',
|
|
152
156
|
},
|
|
153
157
|
]);
|
|
154
158
|
if (proceed === false) {
|
package/dist/cli/index.js
CHANGED
|
@@ -81,6 +81,7 @@ async function createCli() {
|
|
|
81
81
|
.command('apply')
|
|
82
82
|
.description('Apply a snapshot file to the current database')
|
|
83
83
|
.option('-y, --yes', `Assume "yes" as answer to all prompts and run non-interactively`)
|
|
84
|
+
.option('-d, --dry-run', 'Plan and log changes to be applied', false)
|
|
84
85
|
.argument('<path>', 'Path to snapshot file')
|
|
85
86
|
.action(apply_1.apply);
|
|
86
87
|
await emitter_1.default.emitInit('cli.after', { program });
|
|
@@ -14,6 +14,9 @@ const use_collection_1 = __importDefault(require("../middleware/use-collection")
|
|
|
14
14
|
const services_1 = require("../services");
|
|
15
15
|
const assets_1 = require("../types/assets");
|
|
16
16
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
17
|
+
const helmet_1 = __importDefault(require("helmet"));
|
|
18
|
+
const lodash_2 = require("lodash");
|
|
19
|
+
const get_config_from_env_1 = require("../utils/get-config-from-env");
|
|
17
20
|
const router = (0, express_1.Router)();
|
|
18
21
|
router.use((0, use_collection_1.default)('directus_files'));
|
|
19
22
|
router.get('/:pk',
|
|
@@ -88,7 +91,12 @@ router.get('/:pk',
|
|
|
88
91
|
return next();
|
|
89
92
|
throw new exceptions_1.InvalidQueryException(`Dynamic asset generation has been disabled for this project.`);
|
|
90
93
|
}
|
|
91
|
-
}),
|
|
94
|
+
}), helmet_1.default.contentSecurityPolicy((0, lodash_2.merge)({
|
|
95
|
+
useDefaults: false,
|
|
96
|
+
directives: {
|
|
97
|
+
defaultSrc: ['none'],
|
|
98
|
+
},
|
|
99
|
+
}, (0, get_config_from_env_1.getConfigFromEnv)('ASSETS_CONTENT_SECURITY_POLICY'))),
|
|
92
100
|
// Return file
|
|
93
101
|
(0, async_handler_1.default)(async (req, res) => {
|
|
94
102
|
var _a, _b;
|
|
@@ -95,12 +95,29 @@ router.post('/import/:collection', collection_exists_1.default, (0, async_handle
|
|
|
95
95
|
busboy.on('error', (err) => next(err));
|
|
96
96
|
req.pipe(busboy);
|
|
97
97
|
}));
|
|
98
|
+
router.post('/export/:collection', collection_exists_1.default, (0, async_handler_1.default)(async (req, res, next) => {
|
|
99
|
+
if (!req.body.query) {
|
|
100
|
+
throw new exceptions_1.InvalidPayloadException(`"query" is required.`);
|
|
101
|
+
}
|
|
102
|
+
if (!req.body.format) {
|
|
103
|
+
throw new exceptions_1.InvalidPayloadException(`"format" is required.`);
|
|
104
|
+
}
|
|
105
|
+
const service = new services_1.ExportService({
|
|
106
|
+
accountability: req.accountability,
|
|
107
|
+
schema: req.schema,
|
|
108
|
+
});
|
|
109
|
+
// We're not awaiting this, as it's supposed to run async in the background
|
|
110
|
+
service.exportToFile(req.params.collection, req.body.query, req.body.format, {
|
|
111
|
+
file: req.body.file,
|
|
112
|
+
});
|
|
113
|
+
return next();
|
|
114
|
+
}), respond_1.respond);
|
|
98
115
|
router.post('/cache/clear', (0, async_handler_1.default)(async (req, res) => {
|
|
99
116
|
var _a;
|
|
100
117
|
if (((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.admin) !== true) {
|
|
101
118
|
throw new exceptions_1.ForbiddenException();
|
|
102
119
|
}
|
|
103
|
-
await (0, cache_1.flushCaches)();
|
|
120
|
+
await (0, cache_1.flushCaches)(true);
|
|
104
121
|
res.status(200).end();
|
|
105
122
|
}));
|
|
106
123
|
exports.default = router;
|
package/dist/database/run-ast.js
CHANGED
|
@@ -64,7 +64,10 @@ async function runAST(originalAST, schema, options) {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
67
|
-
|
|
67
|
+
const node = (0, lodash_1.merge)({}, nestedNode, {
|
|
68
|
+
query: { limit: -1 },
|
|
69
|
+
});
|
|
70
|
+
nestedItems = (await runAST(node, schema, { knex, nested: true }));
|
|
68
71
|
if (nestedItems) {
|
|
69
72
|
// Merge all fetched nested records with the parent items
|
|
70
73
|
items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
|
|
@@ -238,6 +241,9 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
|
|
|
238
241
|
((_a = nestedItem[nestedNode.relation.field]) === null || _a === void 0 ? void 0 : _a[schema.collections[nestedNode.relation.related_collection].primary]) == parentItem[schema.collections[nestedNode.relation.related_collection].primary]);
|
|
239
242
|
});
|
|
240
243
|
parentItem[nestedNode.fieldKey].push(...itemChildren);
|
|
244
|
+
if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
|
|
245
|
+
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
|
|
246
|
+
}
|
|
241
247
|
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, (_a = nestedNode.query.limit) !== null && _a !== void 0 ? _a : 100);
|
|
242
248
|
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
|
|
243
249
|
// This is pre-filled in get-ast-from-query
|
package/dist/env.js
CHANGED
|
@@ -35,8 +35,8 @@ const defaults = {
|
|
|
35
35
|
REFRESH_TOKEN_COOKIE_SAME_SITE: 'lax',
|
|
36
36
|
REFRESH_TOKEN_COOKIE_NAME: 'directus_refresh_token',
|
|
37
37
|
ROOT_REDIRECT: './admin',
|
|
38
|
-
CORS_ENABLED:
|
|
39
|
-
CORS_ORIGIN:
|
|
38
|
+
CORS_ENABLED: false,
|
|
39
|
+
CORS_ORIGIN: false,
|
|
40
40
|
CORS_METHODS: 'GET,POST,PATCH,DELETE',
|
|
41
41
|
CORS_ALLOWED_HEADERS: 'Content-Type,Authorization',
|
|
42
42
|
CORS_EXPOSED_HEADERS: 'Content-Range',
|
|
@@ -65,8 +65,10 @@ const defaults = {
|
|
|
65
65
|
ASSETS_TRANSFORM_MAX_OPERATIONS: 5,
|
|
66
66
|
IP_TRUST_PROXY: true,
|
|
67
67
|
IP_CUSTOM_HEADER: false,
|
|
68
|
+
IMPORT_IP_DENY_LIST: '0.0.0.0',
|
|
68
69
|
SERVE_APP: true,
|
|
69
70
|
RELATIONAL_BATCH_SIZE: 25000,
|
|
71
|
+
EXPORT_BATCH_SIZE: 5000,
|
|
70
72
|
};
|
|
71
73
|
// Allows us to force certain environment variable into a type, instead of relying
|
|
72
74
|
// on the auto-parsed type in processValues. ref #3705
|
|
@@ -79,6 +81,7 @@ const typeMap = {
|
|
|
79
81
|
DB_DATABASE: 'string',
|
|
80
82
|
DB_PORT: 'number',
|
|
81
83
|
DB_EXCLUDE_TABLES: 'array',
|
|
84
|
+
IMPORT_IP_DENY_LIST: 'array',
|
|
82
85
|
};
|
|
83
86
|
let env = {
|
|
84
87
|
...defaults,
|
|
@@ -38,6 +38,7 @@ function extractError(error) {
|
|
|
38
38
|
}
|
|
39
39
|
exports.extractError = extractError;
|
|
40
40
|
function uniqueViolation(error) {
|
|
41
|
+
var _a, _b, _c, _d, _e;
|
|
41
42
|
const betweenQuotes = /'([^']+)'/g;
|
|
42
43
|
const matches = error.sqlMessage.match(betweenQuotes);
|
|
43
44
|
if (!matches)
|
|
@@ -49,13 +50,13 @@ function uniqueViolation(error) {
|
|
|
49
50
|
*/
|
|
50
51
|
/** MySQL 8+ style error message */
|
|
51
52
|
if (matches[1].includes('.')) {
|
|
52
|
-
const collection = matches[1].slice(1, -1).split('.')[0];
|
|
53
|
+
const collection = (_a = matches[1]) === null || _a === void 0 ? void 0 : _a.slice(1, -1).split('.')[0];
|
|
53
54
|
let field = null;
|
|
54
|
-
const indexName = matches[1].slice(1, -1).split('.')[1];
|
|
55
|
+
const indexName = (_b = matches[1]) === null || _b === void 0 ? void 0 : _b.slice(1, -1).split('.')[1];
|
|
55
56
|
if ((indexName === null || indexName === void 0 ? void 0 : indexName.startsWith(`${collection}_`)) && indexName.endsWith('_unique')) {
|
|
56
|
-
field = indexName.slice(collection.length + 1, -7);
|
|
57
|
+
field = indexName === null || indexName === void 0 ? void 0 : indexName.slice(collection.length + 1, -7);
|
|
57
58
|
}
|
|
58
|
-
const invalid = matches[0].slice(1, -1);
|
|
59
|
+
const invalid = (_c = matches[0]) === null || _c === void 0 ? void 0 : _c.slice(1, -1);
|
|
59
60
|
return new record_not_unique_1.RecordNotUniqueException(field, {
|
|
60
61
|
collection,
|
|
61
62
|
field,
|
|
@@ -64,13 +65,13 @@ function uniqueViolation(error) {
|
|
|
64
65
|
}
|
|
65
66
|
else {
|
|
66
67
|
/** MySQL 5.7 style error message */
|
|
67
|
-
const indexName = matches[1].slice(1, -1);
|
|
68
|
+
const indexName = (_d = matches[1]) === null || _d === void 0 ? void 0 : _d.slice(1, -1);
|
|
68
69
|
const collection = indexName.split('_')[0];
|
|
69
70
|
let field = null;
|
|
70
71
|
if ((indexName === null || indexName === void 0 ? void 0 : indexName.startsWith(`${collection}_`)) && indexName.endsWith('_unique')) {
|
|
71
|
-
field = indexName.slice(collection.length + 1, -7);
|
|
72
|
+
field = indexName === null || indexName === void 0 ? void 0 : indexName.slice(collection.length + 1, -7);
|
|
72
73
|
}
|
|
73
|
-
const invalid = matches[0].slice(1, -1);
|
|
74
|
+
const invalid = (_e = matches[0]) === null || _e === void 0 ? void 0 : _e.slice(1, -1);
|
|
74
75
|
return new record_not_unique_1.RecordNotUniqueException(field, {
|
|
75
76
|
collection,
|
|
76
77
|
field,
|
|
@@ -79,57 +80,61 @@ function uniqueViolation(error) {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
function numericValueOutOfRange(error) {
|
|
83
|
+
var _a, _b;
|
|
82
84
|
const betweenTicks = /`([^`]+)`/g;
|
|
83
85
|
const betweenQuotes = /'([^']+)'/g;
|
|
84
86
|
const tickMatches = error.sql.match(betweenTicks);
|
|
85
87
|
const quoteMatches = error.sqlMessage.match(betweenQuotes);
|
|
86
88
|
if (!tickMatches || !quoteMatches)
|
|
87
89
|
return error;
|
|
88
|
-
const collection = tickMatches[0].slice(1, -1);
|
|
89
|
-
const field = quoteMatches[0].slice(1, -1);
|
|
90
|
+
const collection = (_a = tickMatches[0]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
|
|
91
|
+
const field = (_b = quoteMatches[0]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
|
|
90
92
|
return new value_out_of_range_1.ValueOutOfRangeException(field, {
|
|
91
93
|
collection,
|
|
92
94
|
field,
|
|
93
95
|
});
|
|
94
96
|
}
|
|
95
97
|
function valueLimitViolation(error) {
|
|
98
|
+
var _a, _b;
|
|
96
99
|
const betweenTicks = /`([^`]+)`/g;
|
|
97
100
|
const betweenQuotes = /'([^']+)'/g;
|
|
98
101
|
const tickMatches = error.sql.match(betweenTicks);
|
|
99
102
|
const quoteMatches = error.sqlMessage.match(betweenQuotes);
|
|
100
103
|
if (!tickMatches || !quoteMatches)
|
|
101
104
|
return error;
|
|
102
|
-
const collection = tickMatches[0].slice(1, -1);
|
|
103
|
-
const field = quoteMatches[0].slice(1, -1);
|
|
105
|
+
const collection = (_a = tickMatches[0]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
|
|
106
|
+
const field = (_b = quoteMatches[0]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
|
|
104
107
|
return new value_too_long_1.ValueTooLongException(field, {
|
|
105
108
|
collection,
|
|
106
109
|
field,
|
|
107
110
|
});
|
|
108
111
|
}
|
|
109
112
|
function notNullViolation(error) {
|
|
113
|
+
var _a, _b;
|
|
110
114
|
const betweenTicks = /`([^`]+)`/g;
|
|
111
115
|
const betweenQuotes = /'([^']+)'/g;
|
|
112
116
|
const tickMatches = error.sql.match(betweenTicks);
|
|
113
117
|
const quoteMatches = error.sqlMessage.match(betweenQuotes);
|
|
114
118
|
if (!tickMatches || !quoteMatches)
|
|
115
119
|
return error;
|
|
116
|
-
const collection = tickMatches[0].slice(1, -1);
|
|
117
|
-
const field = quoteMatches[0].slice(1, -1);
|
|
120
|
+
const collection = (_a = tickMatches[0]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
|
|
121
|
+
const field = (_b = quoteMatches[0]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
|
|
118
122
|
return new not_null_violation_1.NotNullViolationException(field, {
|
|
119
123
|
collection,
|
|
120
124
|
field,
|
|
121
125
|
});
|
|
122
126
|
}
|
|
123
127
|
function foreignKeyViolation(error) {
|
|
128
|
+
var _a, _b, _c;
|
|
124
129
|
const betweenTicks = /`([^`]+)`/g;
|
|
125
130
|
const betweenParens = /\(([^)]+)\)/g;
|
|
126
131
|
const tickMatches = error.sqlMessage.match(betweenTicks);
|
|
127
132
|
const parenMatches = error.sql.match(betweenParens);
|
|
128
133
|
if (!tickMatches || !parenMatches)
|
|
129
134
|
return error;
|
|
130
|
-
const collection = tickMatches[1].slice(1, -1);
|
|
131
|
-
const field = tickMatches[3].slice(1, -1);
|
|
132
|
-
const invalid = parenMatches[1].slice(1, -1);
|
|
135
|
+
const collection = (_a = tickMatches[1]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
|
|
136
|
+
const field = (_b = tickMatches[3]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
|
|
137
|
+
const invalid = (_c = parenMatches[1]) === null || _c === void 0 ? void 0 : _c.slice(1, -1);
|
|
133
138
|
return new invalid_foreign_key_1.InvalidForeignKeyException(field, {
|
|
134
139
|
collection,
|
|
135
140
|
field,
|
|
@@ -137,12 +142,13 @@ function foreignKeyViolation(error) {
|
|
|
137
142
|
});
|
|
138
143
|
}
|
|
139
144
|
function containsNullValues(error) {
|
|
145
|
+
var _a;
|
|
140
146
|
const betweenTicks = /`([^`]+)`/g;
|
|
141
147
|
// Normally, we shouldn't read from the executed SQL. In this case, we're altering a single
|
|
142
148
|
// column, so we shouldn't have the problem where multiple columns are altered at the same time
|
|
143
149
|
const tickMatches = error.sql.match(betweenTicks);
|
|
144
150
|
if (!tickMatches)
|
|
145
151
|
return error;
|
|
146
|
-
const field = tickMatches[1].slice(1, -1);
|
|
152
|
+
const field = (_a = tickMatches[1]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
|
|
147
153
|
return new contains_null_values_1.ContainsNullValuesException(field);
|
|
148
154
|
}
|
|
@@ -4,16 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.respond = void 0;
|
|
7
|
-
const json2csv_1 = require("json2csv");
|
|
8
7
|
const ms_1 = __importDefault(require("ms"));
|
|
9
|
-
const stream_1 = require("stream");
|
|
10
8
|
const cache_1 = require("../cache");
|
|
11
9
|
const env_1 = __importDefault(require("../env"));
|
|
12
10
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
13
11
|
const get_cache_key_1 = require("../utils/get-cache-key");
|
|
14
|
-
const js2xmlparser_1 = require("js2xmlparser");
|
|
15
12
|
const get_cache_headers_1 = require("../utils/get-cache-headers");
|
|
16
13
|
const logger_1 = __importDefault(require("../logger"));
|
|
14
|
+
const services_1 = require("../services");
|
|
15
|
+
const get_date_formatted_1 = require("../utils/get-date-formatted");
|
|
17
16
|
exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
18
17
|
var _a, _b, _c;
|
|
19
18
|
const { cache } = (0, cache_1.getCache)();
|
|
@@ -39,6 +38,7 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
|
39
38
|
res.setHeader('Vary', 'Origin, Cache-Control');
|
|
40
39
|
}
|
|
41
40
|
if (req.sanitizedQuery.export) {
|
|
41
|
+
const exportService = new services_1.ExportService({ accountability: req.accountability, schema: req.schema });
|
|
42
42
|
let filename = '';
|
|
43
43
|
if (req.collection) {
|
|
44
44
|
filename += req.collection;
|
|
@@ -46,32 +46,21 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
|
46
46
|
else {
|
|
47
47
|
filename += 'Export';
|
|
48
48
|
}
|
|
49
|
-
filename += ' ' + getDateFormatted();
|
|
49
|
+
filename += ' ' + (0, get_date_formatted_1.getDateFormatted)();
|
|
50
50
|
if (req.sanitizedQuery.export === 'json') {
|
|
51
51
|
res.attachment(`${filename}.json`);
|
|
52
52
|
res.set('Content-Type', 'application/json');
|
|
53
|
-
return res.status(200).send(
|
|
53
|
+
return res.status(200).send(exportService.transform((_a = res.locals.payload) === null || _a === void 0 ? void 0 : _a.data, 'json'));
|
|
54
54
|
}
|
|
55
55
|
if (req.sanitizedQuery.export === 'xml') {
|
|
56
56
|
res.attachment(`${filename}.xml`);
|
|
57
57
|
res.set('Content-Type', 'text/xml');
|
|
58
|
-
return res.status(200).send(
|
|
58
|
+
return res.status(200).send(exportService.transform((_b = res.locals.payload) === null || _b === void 0 ? void 0 : _b.data, 'xml'));
|
|
59
59
|
}
|
|
60
60
|
if (req.sanitizedQuery.export === 'csv') {
|
|
61
61
|
res.attachment(`${filename}.csv`);
|
|
62
62
|
res.set('Content-Type', 'text/csv');
|
|
63
|
-
|
|
64
|
-
if (!((_c = res.locals.payload) === null || _c === void 0 ? void 0 : _c.data) || res.locals.payload.data.length === 0) {
|
|
65
|
-
stream.end(Buffer.from(''));
|
|
66
|
-
return stream.pipe(res);
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
stream.end(Buffer.from(JSON.stringify(res.locals.payload.data), 'utf-8'));
|
|
70
|
-
const json2csv = new json2csv_1.Transform({
|
|
71
|
-
transforms: [json2csv_1.transforms.flatten({ separator: '.' })],
|
|
72
|
-
});
|
|
73
|
-
return stream.pipe(json2csv).pipe(res);
|
|
74
|
-
}
|
|
63
|
+
return res.status(200).send(exportService.transform((_c = res.locals.payload) === null || _c === void 0 ? void 0 : _c.data, 'csv'));
|
|
75
64
|
}
|
|
76
65
|
}
|
|
77
66
|
if (Buffer.isBuffer(res.locals.payload)) {
|
|
@@ -84,13 +73,3 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
|
84
73
|
return res.status(204).end();
|
|
85
74
|
}
|
|
86
75
|
});
|
|
87
|
-
function getDateFormatted() {
|
|
88
|
-
const date = new Date();
|
|
89
|
-
let month = String(date.getMonth() + 1);
|
|
90
|
-
if (month.length === 1)
|
|
91
|
-
month = '0' + month;
|
|
92
|
-
let day = String(date.getDate());
|
|
93
|
-
if (day.length === 1)
|
|
94
|
-
day = '0' + day;
|
|
95
|
-
return `${date.getFullYear()}-${month}-${day} at ${date.getHours()}.${date.getMinutes()}.${date.getSeconds()}`;
|
|
96
|
-
}
|
|
@@ -129,7 +129,7 @@ class CollectionsService {
|
|
|
129
129
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
130
130
|
await this.cache.clear();
|
|
131
131
|
}
|
|
132
|
-
await
|
|
132
|
+
await (0, cache_1.clearSystemCache)();
|
|
133
133
|
return payload.collection;
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
@@ -152,7 +152,7 @@ class CollectionsService {
|
|
|
152
152
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
153
153
|
await this.cache.clear();
|
|
154
154
|
}
|
|
155
|
-
await
|
|
155
|
+
await (0, cache_1.clearSystemCache)();
|
|
156
156
|
return collections;
|
|
157
157
|
}
|
|
158
158
|
/**
|
|
@@ -275,7 +275,7 @@ class CollectionsService {
|
|
|
275
275
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
276
276
|
await this.cache.clear();
|
|
277
277
|
}
|
|
278
|
-
await
|
|
278
|
+
await (0, cache_1.clearSystemCache)();
|
|
279
279
|
return collectionKey;
|
|
280
280
|
}
|
|
281
281
|
/**
|
|
@@ -298,7 +298,7 @@ class CollectionsService {
|
|
|
298
298
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
299
299
|
await this.cache.clear();
|
|
300
300
|
}
|
|
301
|
-
await
|
|
301
|
+
await (0, cache_1.clearSystemCache)();
|
|
302
302
|
return collectionKeys;
|
|
303
303
|
}
|
|
304
304
|
/**
|
|
@@ -379,7 +379,7 @@ class CollectionsService {
|
|
|
379
379
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
380
380
|
await this.cache.clear();
|
|
381
381
|
}
|
|
382
|
-
await
|
|
382
|
+
await (0, cache_1.clearSystemCache)();
|
|
383
383
|
return collectionKey;
|
|
384
384
|
}
|
|
385
385
|
/**
|
|
@@ -402,7 +402,7 @@ class CollectionsService {
|
|
|
402
402
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
|
|
403
403
|
await this.cache.clear();
|
|
404
404
|
}
|
|
405
|
-
await
|
|
405
|
+
await (0, cache_1.clearSystemCache)();
|
|
406
406
|
return collectionKeys;
|
|
407
407
|
}
|
|
408
408
|
}
|
package/dist/services/fields.js
CHANGED
|
@@ -249,7 +249,7 @@ class FieldsService {
|
|
|
249
249
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
250
250
|
await this.cache.clear();
|
|
251
251
|
}
|
|
252
|
-
await
|
|
252
|
+
await (0, cache_1.clearSystemCache)();
|
|
253
253
|
}
|
|
254
254
|
async updateField(collection, field) {
|
|
255
255
|
if (this.accountability && this.accountability.admin !== true) {
|
|
@@ -300,7 +300,7 @@ class FieldsService {
|
|
|
300
300
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
301
301
|
await this.cache.clear();
|
|
302
302
|
}
|
|
303
|
-
await
|
|
303
|
+
await (0, cache_1.clearSystemCache)();
|
|
304
304
|
emitter_1.default.emitAction(`fields.update`, {
|
|
305
305
|
payload: hookAdjustedField,
|
|
306
306
|
keys: [hookAdjustedField.field],
|
|
@@ -395,7 +395,7 @@ class FieldsService {
|
|
|
395
395
|
if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
|
|
396
396
|
await this.cache.clear();
|
|
397
397
|
}
|
|
398
|
-
await
|
|
398
|
+
await (0, cache_1.clearSystemCache)();
|
|
399
399
|
emitter_1.default.emitAction('fields.delete', {
|
|
400
400
|
payload: [field],
|
|
401
401
|
collection: collection,
|