directus 9.0.0-rc.99 → 9.1.1

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.
Files changed (130) hide show
  1. package/dist/app.js +23 -16
  2. package/dist/auth/drivers/index.d.ts +1 -0
  3. package/dist/auth/drivers/index.js +1 -0
  4. package/dist/auth/drivers/ldap.d.ts +21 -0
  5. package/dist/auth/drivers/ldap.js +322 -0
  6. package/dist/auth/drivers/local.d.ts +1 -1
  7. package/dist/auth/drivers/local.js +3 -3
  8. package/dist/auth/drivers/oauth2.d.ts +1 -1
  9. package/dist/auth/drivers/oauth2.js +29 -22
  10. package/dist/auth/drivers/openid.d.ts +1 -1
  11. package/dist/auth/drivers/openid.js +34 -12
  12. package/dist/auth.js +2 -0
  13. package/dist/cache.d.ts +1 -1
  14. package/dist/cache.js +7 -7
  15. package/dist/cli/commands/init/index.js +1 -1
  16. package/dist/cli/index.js +3 -3
  17. package/dist/cli/index.test.js +10 -5
  18. package/dist/constants.js +1 -1
  19. package/dist/controllers/auth.js +3 -0
  20. package/dist/controllers/extensions.js +2 -0
  21. package/dist/controllers/files.js +19 -8
  22. package/dist/controllers/not-found.js +8 -2
  23. package/dist/controllers/notifications.d.ts +2 -0
  24. package/dist/controllers/notifications.js +147 -0
  25. package/dist/controllers/utils.js +11 -1
  26. package/dist/database/helpers/date.d.ts +8 -0
  27. package/dist/database/helpers/date.js +44 -0
  28. package/dist/database/helpers/geometry.d.ts +4 -2
  29. package/dist/database/helpers/geometry.js +48 -27
  30. package/dist/database/index.d.ts +1 -1
  31. package/dist/database/index.js +15 -21
  32. package/dist/database/migrations/20211016A-add-webhook-headers.d.ts +3 -0
  33. package/dist/database/migrations/20211016A-add-webhook-headers.js +15 -0
  34. package/dist/database/migrations/20211103A-set-unique-to-user-token.d.ts +3 -0
  35. package/dist/database/migrations/20211103A-set-unique-to-user-token.js +15 -0
  36. package/dist/database/migrations/20211103B-update-special-geometry.d.ts +3 -0
  37. package/dist/database/migrations/20211103B-update-special-geometry.js +25 -0
  38. package/dist/database/migrations/20211104A-remove-collections-listing.d.ts +3 -0
  39. package/dist/database/migrations/20211104A-remove-collections-listing.js +15 -0
  40. package/dist/database/migrations/20211118A-add-notifications.d.ts +3 -0
  41. package/dist/database/migrations/20211118A-add-notifications.js +28 -0
  42. package/dist/database/migrations/run.d.ts +1 -1
  43. package/dist/database/migrations/run.js +10 -4
  44. package/dist/database/run-ast.js +5 -19
  45. package/dist/database/seeds/run.js +4 -2
  46. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +14 -0
  47. package/dist/database/system-data/collections/collections.yaml +2 -0
  48. package/dist/database/system-data/fields/activity.yaml +0 -2
  49. package/dist/database/system-data/fields/files.yaml +0 -1
  50. package/dist/database/system-data/fields/notifications.yaml +12 -0
  51. package/dist/database/system-data/fields/roles.yaml +0 -53
  52. package/dist/database/system-data/fields/settings.yaml +65 -69
  53. package/dist/database/system-data/fields/users.yaml +5 -1
  54. package/dist/database/system-data/fields/webhooks.yaml +25 -12
  55. package/dist/database/system-data/relations/relations.yaml +6 -0
  56. package/dist/emitter.d.ts +18 -8
  57. package/dist/emitter.js +68 -23
  58. package/dist/env.js +1 -0
  59. package/dist/exceptions/database/translate.js +26 -5
  60. package/dist/extensions.js +50 -27
  61. package/dist/index.d.ts +3 -0
  62. package/dist/index.js +20 -0
  63. package/dist/mailer.js +12 -3
  64. package/dist/middleware/authenticate.js +48 -48
  65. package/dist/middleware/error-handler.js +10 -3
  66. package/dist/middleware/get-permissions.d.ts +3 -0
  67. package/dist/middleware/get-permissions.js +15 -0
  68. package/dist/server.js +17 -7
  69. package/dist/services/activity.d.ts +7 -5
  70. package/dist/services/activity.js +82 -3
  71. package/dist/services/authentication.js +35 -49
  72. package/dist/services/authorization.d.ts +1 -1
  73. package/dist/services/authorization.js +13 -13
  74. package/dist/services/collections.d.ts +1 -1
  75. package/dist/services/collections.js +22 -23
  76. package/dist/services/fields.d.ts +1 -1
  77. package/dist/services/fields.js +29 -37
  78. package/dist/services/files.js +10 -11
  79. package/dist/services/graphql.js +11 -8
  80. package/dist/services/import.js +4 -4
  81. package/dist/services/index.d.ts +1 -0
  82. package/dist/services/index.js +1 -0
  83. package/dist/services/items.js +43 -83
  84. package/dist/services/mail/index.js +2 -2
  85. package/dist/services/mail/templates/base.liquid +153 -85
  86. package/dist/services/mail/templates/password-reset.liquid +3 -2
  87. package/dist/services/mail/templates/user-invitation.liquid +4 -4
  88. package/dist/services/meta.js +7 -8
  89. package/dist/services/notifications.d.ts +12 -0
  90. package/dist/services/notifications.js +41 -0
  91. package/dist/services/payload.js +13 -9
  92. package/dist/services/permissions.d.ts +13 -1
  93. package/dist/services/permissions.js +56 -2
  94. package/dist/services/relations.d.ts +1 -1
  95. package/dist/services/relations.js +12 -18
  96. package/dist/services/specifications.js +21 -2
  97. package/dist/services/users.js +1 -0
  98. package/dist/services/utils.js +3 -3
  99. package/dist/services/webhooks.d.ts +2 -2
  100. package/dist/types/auth.d.ts +1 -1
  101. package/dist/types/collection.d.ts +1 -0
  102. package/dist/types/extensions.d.ts +18 -2
  103. package/dist/types/schema.d.ts +2 -2
  104. package/dist/types/webhooks.d.ts +7 -2
  105. package/dist/utils/apply-query.d.ts +3 -3
  106. package/dist/utils/apply-query.js +52 -14
  107. package/dist/utils/apply-snapshot.js +2 -2
  108. package/dist/utils/get-ast-from-query.js +6 -6
  109. package/dist/utils/get-default-index-name.js +5 -6
  110. package/dist/utils/get-default-value.js +1 -1
  111. package/dist/utils/get-local-type.d.ts +2 -7
  112. package/dist/utils/get-local-type.js +106 -112
  113. package/dist/utils/get-permissions.d.ts +3 -0
  114. package/dist/utils/get-permissions.js +106 -0
  115. package/dist/utils/get-schema.js +11 -51
  116. package/dist/utils/get-simple-hash.d.ts +5 -0
  117. package/dist/utils/get-simple-hash.js +15 -0
  118. package/dist/utils/md.d.ts +4 -0
  119. package/dist/utils/md.js +15 -0
  120. package/dist/utils/reduce-schema.d.ts +2 -2
  121. package/dist/utils/reduce-schema.js +7 -10
  122. package/dist/utils/sanitize-query.js +3 -3
  123. package/dist/utils/user-name.d.ts +2 -0
  124. package/dist/utils/user-name.js +16 -0
  125. package/dist/utils/validate-query.js +4 -0
  126. package/dist/webhooks.js +18 -9
  127. package/package.json +39 -28
  128. package/dist/utils/geometry.d.ts +0 -2
  129. package/dist/utils/geometry.js +0 -20
  130. package/index.js +0 -5
@@ -31,6 +31,12 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
31
31
  this.client = new Promise((resolve, reject) => {
32
32
  openid_client_1.Issuer.discover(issuerUrl)
33
33
  .then((issuer) => {
34
+ const supportedTypes = issuer.metadata.response_types_supported;
35
+ if (!(supportedTypes === null || supportedTypes === void 0 ? void 0 : supportedTypes.includes('code'))) {
36
+ reject(new exceptions_1.InvalidConfigException('OpenID provider does not support required code flow', {
37
+ provider: additionalConfig.provider,
38
+ }));
39
+ }
34
40
  resolve(new issuer.Client({
35
41
  client_id: clientId,
36
42
  client_secret: clientSecret,
@@ -48,10 +54,13 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
48
54
  var _a;
49
55
  try {
50
56
  const client = await this.client;
57
+ const codeChallenge = openid_client_1.generators.codeChallenge(codeVerifier);
51
58
  return client.authorizationUrl({
52
59
  scope: (_a = this.config.scope) !== null && _a !== void 0 ? _a : 'openid profile email',
53
- code_challenge: openid_client_1.generators.codeChallenge(codeVerifier),
60
+ code_challenge: codeChallenge,
54
61
  code_challenge_method: 'S256',
62
+ // Some providers require state even with PKCE
63
+ state: codeChallenge,
55
64
  access_type: 'offline',
56
65
  });
57
66
  }
@@ -63,8 +72,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
63
72
  const user = await this.knex
64
73
  .select('id')
65
74
  .from('directus_users')
66
- .whereRaw('LOWER(??) = ?', ['email', identifier.toLowerCase()])
67
- .orWhereRaw('LOWER(??) = ?', ['external_identifier', identifier.toLowerCase()])
75
+ .whereRaw('LOWER(??) = ?', ['external_identifier', identifier.toLowerCase()])
68
76
  .first();
69
77
  return user === null || user === void 0 ? void 0 : user.id;
70
78
  }
@@ -77,8 +85,14 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
77
85
  let userInfo;
78
86
  try {
79
87
  const client = await this.client;
80
- tokenSet = await client.callback(this.redirectUrl, { code: payload.code }, { code_verifier: payload.codeVerifier });
81
- userInfo = await client.userinfo(tokenSet);
88
+ tokenSet = await client.callback(this.redirectUrl, { code: payload.code, state: payload.state }, { code_verifier: payload.codeVerifier, state: openid_client_1.generators.codeChallenge(payload.codeVerifier) });
89
+ const issuer = client.issuer;
90
+ if (issuer.metadata.userinfo_endpoint) {
91
+ userInfo = await client.userinfo(tokenSet.access_token);
92
+ }
93
+ else {
94
+ userInfo = tokenSet.claims();
95
+ }
82
96
  }
83
97
  catch (e) {
84
98
  throw handleError(e);
@@ -106,21 +120,19 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
106
120
  if (!allowPublicRegistration || !isEmailVerified) {
107
121
  throw new exceptions_1.InvalidCredentialsException();
108
122
  }
109
- // If email matches identifier, don't set "external_identifier"
110
- const emailIsIdentifier = (email === null || email === void 0 ? void 0 : email.toLowerCase()) === identifier.toLowerCase();
111
123
  await this.usersService.createOne({
112
124
  provider: this.config.provider,
113
125
  first_name: userInfo.given_name,
114
126
  last_name: userInfo.family_name,
115
127
  email: email,
116
- external_identifier: !emailIsIdentifier ? identifier : undefined,
128
+ external_identifier: identifier,
117
129
  role: this.config.defaultRoleId,
118
130
  auth_data: tokenSet.refresh_token && JSON.stringify({ refreshToken: tokenSet.refresh_token }),
119
131
  });
120
132
  return (await this.fetchUserId(identifier));
121
133
  }
122
- async login(user, sessionData) {
123
- return this.refresh(user, sessionData);
134
+ async login(user) {
135
+ return this.refresh(user, null);
124
136
  }
125
137
  async refresh(user, sessionData) {
126
138
  let authData = user.auth_data;
@@ -181,8 +193,14 @@ function createOpenIDAuthRouter(providerName) {
181
193
  }), respond_1.respond);
182
194
  router.get('/callback', (0, async_handler_1.default)(async (req, res, next) => {
183
195
  var _a;
184
- const token = req.cookies[`openid.${providerName}`];
185
- const { verifier, redirect } = jsonwebtoken_1.default.verify(token, env_1.default.SECRET, { issuer: 'directus' });
196
+ let tokenData;
197
+ try {
198
+ tokenData = jsonwebtoken_1.default.verify(req.cookies[`openid.${providerName}`], env_1.default.SECRET, { issuer: 'directus' });
199
+ }
200
+ catch (e) {
201
+ throw new exceptions_1.InvalidCredentialsException();
202
+ }
203
+ const { verifier, redirect } = tokenData;
186
204
  const authenticationService = new services_1.AuthenticationService({
187
205
  accountability: {
188
206
  ip: req.ip,
@@ -194,9 +212,13 @@ function createOpenIDAuthRouter(providerName) {
194
212
  let authResponse;
195
213
  try {
196
214
  res.clearCookie(`openid.${providerName}`);
215
+ if (!req.query.code || !req.query.state) {
216
+ logger_1.default.warn(`Couldn't extract OpenID code or state from query: ${JSON.stringify(req.query)}`);
217
+ }
197
218
  authResponse = await authenticationService.login(providerName, {
198
219
  code: req.query.code,
199
220
  codeVerifier: verifier,
221
+ state: req.query.state,
200
222
  });
201
223
  }
202
224
  catch (error) {
package/dist/auth.js CHANGED
@@ -59,5 +59,7 @@ function getProviderInstance(driver, options, config = {}) {
59
59
  return new drivers_1.OAuth2AuthDriver(options, config);
60
60
  case 'openid':
61
61
  return new drivers_1.OpenIDAuthDriver(options, config);
62
+ case 'ldap':
63
+ return new drivers_1.LDAPAuthDriver(options, config);
62
64
  }
63
65
  }
package/dist/cache.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Keyv from 'keyv';
2
2
  export declare function getCache(): {
3
3
  cache: Keyv | null;
4
- schemaCache: Keyv | null;
4
+ systemCache: Keyv;
5
5
  };
6
6
  export declare function flushCaches(): Promise<void>;
package/dist/cache.js CHANGED
@@ -11,23 +11,23 @@ const logger_1 = __importDefault(require("./logger"));
11
11
  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
- let schemaCache = null;
14
+ let systemCache = null;
15
15
  function getCache() {
16
16
  if (env_1.default.CACHE_ENABLED === true && cache === null) {
17
17
  (0, validate_env_1.validateEnv)(['CACHE_NAMESPACE', 'CACHE_TTL', 'CACHE_STORE']);
18
18
  cache = getKeyvInstance((0, ms_1.default)(env_1.default.CACHE_TTL));
19
19
  cache.on('error', (err) => logger_1.default.warn(err, `[cache] ${err}`));
20
20
  }
21
- if (env_1.default.CACHE_SCHEMA !== false && schemaCache === null) {
22
- schemaCache = getKeyvInstance(typeof env_1.default.CACHE_SCHEMA === 'string' ? (0, ms_1.default)(env_1.default.CACHE_SCHEMA) : undefined, '_schema');
23
- schemaCache.on('error', (err) => logger_1.default.warn(err, `[cache] ${err}`));
21
+ if (systemCache === null) {
22
+ systemCache = getKeyvInstance(undefined, '_system');
23
+ systemCache.on('error', (err) => logger_1.default.warn(err, `[cache] ${err}`));
24
24
  }
25
- return { cache, schemaCache };
25
+ return { cache, systemCache };
26
26
  }
27
27
  exports.getCache = getCache;
28
28
  async function flushCaches() {
29
- const { schemaCache, cache } = getCache();
30
- await (schemaCache === null || schemaCache === void 0 ? void 0 : schemaCache.clear());
29
+ const { systemCache, cache } = getCache();
30
+ await (systemCache === null || systemCache === void 0 ? void 0 : systemCache.clear());
31
31
  await (cache === null || cache === void 0 ? void 0 : cache.clear());
32
32
  }
33
33
  exports.flushCaches = flushCaches;
@@ -36,7 +36,7 @@ async function init() {
36
36
  const db = (0, create_db_connection_1.default)(dbClient, credentials);
37
37
  try {
38
38
  await (0, run_2.default)(db);
39
- await (0, run_1.default)(db, 'latest');
39
+ await (0, run_1.default)(db, 'latest', false);
40
40
  }
41
41
  catch (err) {
42
42
  process.stdout.write('\nSomething went wrong while seeding the database:\n');
package/dist/cli/index.js CHANGED
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createCli = void 0;
7
7
  const commander_1 = require("commander");
8
8
  const server_1 = require("../server");
9
- const emitter_1 = require("../emitter");
9
+ const emitter_1 = __importDefault(require("../emitter"));
10
10
  const extensions_1 = require("../extensions");
11
11
  const bootstrap_1 = __importDefault(require("./commands/bootstrap"));
12
12
  const count_1 = __importDefault(require("./commands/count"));
@@ -23,7 +23,7 @@ async function createCli() {
23
23
  const program = new commander_1.Command();
24
24
  const extensionManager = (0, extensions_1.getExtensionManager)();
25
25
  await extensionManager.initialize({ schedule: false });
26
- await (0, emitter_1.emitAsyncSafe)('cli.init.before', { program });
26
+ await emitter_1.default.emitInit('cli.before', { program });
27
27
  program.name('directus').usage('[command] [options]');
28
28
  program.version(pkg.version, '-v, --version');
29
29
  program.command('start').description('Start the Directus API').action(server_1.startServer);
@@ -83,7 +83,7 @@ async function createCli() {
83
83
  .option('-y, --yes', `Assume "yes" as answer to all prompts and run non-interactively`)
84
84
  .argument('<path>', 'Path to snapshot file')
85
85
  .action(apply_1.apply);
86
- await (0, emitter_1.emitAsyncSafe)('cli.init.after', { program });
86
+ await emitter_1.default.emitInit('cli.after', { program });
87
87
  return program;
88
88
  }
89
89
  exports.createCli = createCli;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const _1 = require(".");
3
+ const index_1 = require("./index");
4
4
  jest.mock('../env', () => ({
5
5
  ...jest.requireActual('../env').default,
6
6
  EXTENSIONS_PATH: '',
@@ -16,7 +16,7 @@ jest.mock('@directus/shared/utils/node/get-extensions', () => ({
16
16
  getPackageExtensions: jest.fn(() => Promise.resolve([])),
17
17
  getLocalExtensions: jest.fn(() => Promise.resolve([customCliExtension])),
18
18
  }));
19
- jest.mock(`/hooks/custom-cli/index.js`, () => () => customCliHook, { virtual: true });
19
+ jest.mock(`/hooks/custom-cli/index.js`, () => customCliHook, { virtual: true });
20
20
  const customCliExtension = {
21
21
  path: `/hooks/custom-cli`,
22
22
  name: 'custom-cli',
@@ -26,12 +26,17 @@ const customCliExtension = {
26
26
  };
27
27
  const beforeHook = jest.fn();
28
28
  const afterAction = jest.fn();
29
- const afterHook = jest.fn(({ program }) => program.command('custom').action(afterAction));
30
- const customCliHook = { 'cli.init.before': beforeHook, 'cli.init.after': afterHook };
29
+ const afterHook = jest.fn(({ program }) => {
30
+ program.command('custom').action(afterAction);
31
+ });
32
+ const customCliHook = ({ init }) => {
33
+ init('cli.before', beforeHook);
34
+ init('cli.after', afterHook);
35
+ };
31
36
  const writeOut = jest.fn();
32
37
  const writeErr = jest.fn();
33
38
  const setup = async () => {
34
- const program = await (0, _1.createCli)();
39
+ const program = await (0, index_1.createCli)();
35
40
  program.exitOverride();
36
41
  program.configureOutput({ writeOut, writeErr });
37
42
  return program;
package/dist/constants.js CHANGED
@@ -38,6 +38,6 @@ exports.ASSET_TRANSFORM_QUERY_KEYS = [
38
38
  'withoutEnlargement',
39
39
  ];
40
40
  exports.FILTER_VARIABLES = ['$NOW', '$CURRENT_USER', '$CURRENT_ROLE'];
41
- exports.ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'm2a', 'files', 'files', 'translations'];
41
+ exports.ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'm2a', 'files', 'translations'];
42
42
  exports.DEFAULT_AUTH_PROVIDER = 'default';
43
43
  exports.COLUMN_TRANSFORMS = ['year', 'month', 'day', 'weekday', 'hour', 'minute', 'second'];
@@ -28,6 +28,9 @@ for (const authProvider of authProviders) {
28
28
  case 'openid':
29
29
  authRouter = (0, drivers_1.createOpenIDAuthRouter)(authProvider.name);
30
30
  break;
31
+ case 'ldap':
32
+ authRouter = (0, drivers_1.createLDAPAuthRouter)(authProvider.name);
33
+ break;
31
34
  }
32
35
  if (!authRouter) {
33
36
  logger_1.default.warn(`Couldn't create login router for auth provider "${authProvider.name}"`);
@@ -33,6 +33,8 @@ router.get('/:type/index.js', (0, async_handler_1.default)(async (req, res) => {
33
33
  throw new exceptions_1.RouteNotFoundException(req.path);
34
34
  }
35
35
  res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
36
+ res.setHeader('Cache-Control', 'no-cache');
37
+ res.setHeader('Vary', 'Origin, Cache-Control');
36
38
  res.end(extensionSource);
37
39
  }));
38
40
  exports.default = router;
@@ -21,7 +21,17 @@ router.use((0, use_collection_1.default)('directus_files'));
21
21
  const multipartHandler = (0, async_handler_1.default)(async (req, res, next) => {
22
22
  if (req.is('multipart/form-data') === false)
23
23
  return next();
24
- const busboy = new busboy_1.default({ headers: req.headers });
24
+ let headers;
25
+ if (req.headers['content-type']) {
26
+ headers = req.headers;
27
+ }
28
+ else {
29
+ headers = {
30
+ ...req.headers,
31
+ 'content-type': 'application/octet-stream',
32
+ };
33
+ }
34
+ const busboy = new busboy_1.default({ headers });
25
35
  const savedFiles = [];
26
36
  const service = new services_1.FilesService({ accountability: req.accountability, schema: req.schema });
27
37
  const existingPrimaryKey = req.params.pk || undefined;
@@ -34,16 +44,17 @@ const multipartHandler = (0, async_handler_1.default)(async (req, res, next) =>
34
44
  let payload = {};
35
45
  let fileCount = 0;
36
46
  busboy.on('field', (fieldname, val) => {
37
- if (typeof val === 'string' && val.trim() === 'null')
38
- val = null;
39
- if (typeof val === 'string' && val.trim() === 'false')
40
- val = false;
41
- if (typeof val === 'string' && val.trim() === 'true')
42
- val = true;
47
+ let fieldValue = val;
48
+ if (typeof fieldValue === 'string' && fieldValue.trim() === 'null')
49
+ fieldValue = null;
50
+ if (typeof fieldValue === 'string' && fieldValue.trim() === 'false')
51
+ fieldValue = false;
52
+ if (typeof fieldValue === 'string' && fieldValue.trim() === 'true')
53
+ fieldValue = true;
43
54
  if (fieldname === 'storage') {
44
55
  disk = val;
45
56
  }
46
- payload[fieldname] = val;
57
+ payload[fieldname] = fieldValue;
47
58
  });
48
59
  busboy.on('file', async (fieldname, fileStream, filename, encoding, mimetype) => {
49
60
  fileCount++;
@@ -3,6 +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
+ const database_1 = __importDefault(require("../database"));
6
7
  const emitter_1 = __importDefault(require("../emitter"));
7
8
  const exceptions_1 = require("../exceptions");
8
9
  /**
@@ -17,9 +18,14 @@ const exceptions_1 = require("../exceptions");
17
18
  * @param next
18
19
  */
19
20
  const notFound = async (req, res, next) => {
21
+ var _a;
20
22
  try {
21
- const hooksResult = await emitter_1.default.emitAsync('request.not_found', req, res);
22
- if (hooksResult.reduce((prev, current) => current || prev, false)) {
23
+ const hooksResult = await emitter_1.default.emitFilter('request.not_found', false, { request: req, response: res }, {
24
+ database: (0, database_1.default)(),
25
+ schema: req.schema,
26
+ accountability: (_a = req.accountability) !== null && _a !== void 0 ? _a : null,
27
+ });
28
+ if (hooksResult) {
23
29
  return next();
24
30
  }
25
31
  next(new exceptions_1.RouteNotFoundException(req.path));
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,147 @@
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 express_1 = __importDefault(require("express"));
7
+ const exceptions_1 = require("../exceptions");
8
+ const respond_1 = require("../middleware/respond");
9
+ const use_collection_1 = __importDefault(require("../middleware/use-collection"));
10
+ const validate_batch_1 = require("../middleware/validate-batch");
11
+ const services_1 = require("../services");
12
+ const async_handler_1 = __importDefault(require("../utils/async-handler"));
13
+ const router = express_1.default.Router();
14
+ router.use((0, use_collection_1.default)('directus_notifications'));
15
+ router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
16
+ const service = new services_1.NotificationsService({
17
+ accountability: req.accountability,
18
+ schema: req.schema,
19
+ });
20
+ const savedKeys = [];
21
+ if (Array.isArray(req.body)) {
22
+ const keys = await service.createMany(req.body);
23
+ savedKeys.push(...keys);
24
+ }
25
+ else {
26
+ const key = await service.createOne(req.body);
27
+ savedKeys.push(key);
28
+ }
29
+ try {
30
+ if (Array.isArray(req.body)) {
31
+ const records = await service.readMany(savedKeys, req.sanitizedQuery);
32
+ res.locals.payload = { data: records };
33
+ }
34
+ else {
35
+ const record = await service.readOne(savedKeys[0], req.sanitizedQuery);
36
+ res.locals.payload = { data: record };
37
+ }
38
+ }
39
+ catch (error) {
40
+ if (error instanceof exceptions_1.ForbiddenException) {
41
+ return next();
42
+ }
43
+ throw error;
44
+ }
45
+ return next();
46
+ }), respond_1.respond);
47
+ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
48
+ const service = new services_1.NotificationsService({
49
+ accountability: req.accountability,
50
+ schema: req.schema,
51
+ });
52
+ const metaService = new services_1.MetaService({
53
+ accountability: req.accountability,
54
+ schema: req.schema,
55
+ });
56
+ let result;
57
+ if (req.singleton) {
58
+ result = await service.readSingleton(req.sanitizedQuery);
59
+ }
60
+ else if (req.body.keys) {
61
+ result = await service.readMany(req.body.keys, req.sanitizedQuery);
62
+ }
63
+ else {
64
+ result = await service.readByQuery(req.sanitizedQuery);
65
+ }
66
+ const meta = await metaService.getMetaForQuery('directus_presets', req.sanitizedQuery);
67
+ res.locals.payload = { data: result, meta };
68
+ return next();
69
+ });
70
+ router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
71
+ router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
72
+ router.get('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
73
+ const service = new services_1.NotificationsService({
74
+ accountability: req.accountability,
75
+ schema: req.schema,
76
+ });
77
+ const record = await service.readOne(req.params.pk, req.sanitizedQuery);
78
+ res.locals.payload = { data: record || null };
79
+ return next();
80
+ }), respond_1.respond);
81
+ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handler_1.default)(async (req, res, next) => {
82
+ const service = new services_1.NotificationsService({
83
+ accountability: req.accountability,
84
+ schema: req.schema,
85
+ });
86
+ let keys = [];
87
+ if (req.body.keys) {
88
+ keys = await service.updateMany(req.body.keys, req.body.data);
89
+ }
90
+ else {
91
+ keys = await service.updateByQuery(req.body.query, req.body.data);
92
+ }
93
+ try {
94
+ const result = await service.readMany(keys, req.sanitizedQuery);
95
+ res.locals.payload = { data: result };
96
+ }
97
+ catch (error) {
98
+ if (error instanceof exceptions_1.ForbiddenException) {
99
+ return next();
100
+ }
101
+ throw error;
102
+ }
103
+ return next();
104
+ }), respond_1.respond);
105
+ router.patch('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
106
+ const service = new services_1.NotificationsService({
107
+ accountability: req.accountability,
108
+ schema: req.schema,
109
+ });
110
+ const primaryKey = await service.updateOne(req.params.pk, req.body);
111
+ try {
112
+ const record = await service.readOne(primaryKey, req.sanitizedQuery);
113
+ res.locals.payload = { data: record };
114
+ }
115
+ catch (error) {
116
+ if (error instanceof exceptions_1.ForbiddenException) {
117
+ return next();
118
+ }
119
+ throw error;
120
+ }
121
+ return next();
122
+ }), respond_1.respond);
123
+ router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_handler_1.default)(async (req, res, next) => {
124
+ const service = new services_1.NotificationsService({
125
+ accountability: req.accountability,
126
+ schema: req.schema,
127
+ });
128
+ if (Array.isArray(req.body)) {
129
+ await service.deleteMany(req.body);
130
+ }
131
+ else if (req.body.keys) {
132
+ await service.deleteMany(req.body.keys);
133
+ }
134
+ else {
135
+ await service.deleteByQuery(req.body.query);
136
+ }
137
+ return next();
138
+ }), respond_1.respond);
139
+ router.delete('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
140
+ const service = new services_1.NotificationsService({
141
+ accountability: req.accountability,
142
+ schema: req.schema,
143
+ });
144
+ await service.deleteOne(req.params.pk);
145
+ return next();
146
+ }), respond_1.respond);
147
+ exports.default = router;
@@ -70,7 +70,17 @@ router.post('/import/:collection', collection_exists_1.default, (0, async_handle
70
70
  accountability: req.accountability,
71
71
  schema: req.schema,
72
72
  });
73
- const busboy = new busboy_1.default({ headers: req.headers });
73
+ let headers;
74
+ if (req.headers['content-type']) {
75
+ headers = req.headers;
76
+ }
77
+ else {
78
+ headers = {
79
+ ...req.headers,
80
+ 'content-type': 'application/octet-stream',
81
+ };
82
+ }
83
+ const busboy = new busboy_1.default({ headers });
74
84
  busboy.on('file', async (fieldname, fileStream, filename, encoding, mimetype) => {
75
85
  try {
76
86
  await service.import(req.params.collection, mimetype, fileStream);
@@ -0,0 +1,8 @@
1
+ import { Knex } from 'knex';
2
+ export declare function getDateHelper(): KnexDate;
3
+ declare class KnexDate {
4
+ protected knex: Knex;
5
+ constructor(knex: Knex);
6
+ parseDate(date: string): string;
7
+ }
8
+ export {};
@@ -0,0 +1,44 @@
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
+ exports.getDateHelper = void 0;
7
+ const __1 = __importDefault(require(".."));
8
+ let dateHelper;
9
+ function getDateHelper() {
10
+ if (!dateHelper) {
11
+ const db = (0, __1.default)();
12
+ const client = db.client.config.client;
13
+ const constructor = {
14
+ mysql: KnexDate,
15
+ mariadb: KnexDate,
16
+ sqlite3: KnexDate_SQLITE,
17
+ pg: KnexDate,
18
+ postgres: KnexDate,
19
+ redshift: KnexDate,
20
+ mssql: KnexDate,
21
+ oracledb: KnexDate,
22
+ }[client];
23
+ if (!constructor) {
24
+ throw new Error(`Geometry helper not implemented on ${client}.`);
25
+ }
26
+ dateHelper = new constructor(db);
27
+ }
28
+ return dateHelper;
29
+ }
30
+ exports.getDateHelper = getDateHelper;
31
+ class KnexDate {
32
+ constructor(knex) {
33
+ this.knex = knex;
34
+ }
35
+ parseDate(date) {
36
+ return date;
37
+ }
38
+ }
39
+ class KnexDate_SQLITE extends KnexDate {
40
+ parseDate(date) {
41
+ const newDate = new Date(date);
42
+ return (newDate.getTime() - newDate.getTimezoneOffset() * 60 * 1000).toString();
43
+ }
44
+ }
@@ -1,14 +1,16 @@
1
1
  import { Field, RawField } from '@directus/shared/types';
2
2
  import { Knex } from 'knex';
3
3
  import { GeoJSONGeometry } from 'wellknown';
4
- export declare function getGeometryHelper(): KnexSpatial;
5
- declare class KnexSpatial {
4
+ export declare function getGeometryHelper(database?: Knex): KnexSpatial;
5
+ declare abstract class KnexSpatial {
6
6
  protected knex: Knex;
7
7
  constructor(knex: Knex);
8
+ supported(): boolean | Promise<boolean>;
8
9
  isTrue(expression: Knex.Raw): Knex.Raw<any>;
9
10
  isFalse(expression: Knex.Raw): Knex.Raw<any>;
10
11
  createColumn(table: Knex.CreateTableBuilder, field: RawField | Field): Knex.ColumnBuilder;
11
12
  asText(table: string, column: string): Knex.Raw;
13
+ asGeoJSON?(table: string, column: string): Knex.Raw;
12
14
  fromText(text: string): Knex.Raw;
13
15
  fromGeoJSON(geojson: GeoJSONGeometry): Knex.Raw;
14
16
  _intersects(key: string, geojson: GeoJSONGeometry): Knex.Raw;