directus 9.2.1 → 9.4.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 (93) hide show
  1. package/dist/app.js +5 -3
  2. package/dist/auth/auth.d.ts +4 -6
  3. package/dist/auth/auth.js +5 -9
  4. package/dist/auth/drivers/ldap.d.ts +3 -3
  5. package/dist/auth/drivers/ldap.js +6 -2
  6. package/dist/auth/drivers/local.d.ts +2 -2
  7. package/dist/auth/drivers/local.js +5 -12
  8. package/dist/auth/drivers/oauth2.d.ts +3 -3
  9. package/dist/auth/drivers/oauth2.js +2 -3
  10. package/dist/auth/drivers/openid.d.ts +3 -3
  11. package/dist/auth/drivers/openid.js +2 -3
  12. package/dist/cli/commands/bootstrap/index.js +3 -2
  13. package/dist/cli/commands/init/index.js +3 -7
  14. package/dist/cli/commands/schema/apply.js +1 -1
  15. package/dist/cli/utils/defaults.d.ts +11 -0
  16. package/dist/cli/utils/defaults.js +14 -0
  17. package/dist/constants.d.ts +8 -0
  18. package/dist/constants.js +16 -2
  19. package/dist/controllers/shares.d.ts +2 -0
  20. package/dist/controllers/shares.js +212 -0
  21. package/dist/controllers/users.js +21 -9
  22. package/dist/database/migrations/20211211A-add-shares.d.ts +3 -0
  23. package/dist/database/migrations/20211211A-add-shares.js +38 -0
  24. package/dist/database/run-ast.js +5 -5
  25. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -15
  26. package/dist/database/system-data/app-access-permissions/index.d.ts +1 -0
  27. package/dist/database/system-data/app-access-permissions/index.js +4 -2
  28. package/dist/database/system-data/app-access-permissions/schema-access-permissions.yaml +17 -0
  29. package/dist/database/system-data/collections/collections.yaml +3 -0
  30. package/dist/database/system-data/fields/_defaults.yaml +2 -0
  31. package/dist/database/system-data/fields/sessions.yaml +1 -1
  32. package/dist/database/system-data/fields/settings.yaml +9 -0
  33. package/dist/database/system-data/fields/shares.yaml +77 -0
  34. package/dist/database/system-data/fields/users.yaml +1 -1
  35. package/dist/database/system-data/relations/relations.yaml +15 -0
  36. package/dist/emitter.d.ts +3 -2
  37. package/dist/emitter.js +13 -6
  38. package/dist/env.js +1 -1
  39. package/dist/exceptions/index.d.ts +1 -0
  40. package/dist/exceptions/index.js +1 -0
  41. package/dist/exceptions/unexpected-response.d.ts +4 -0
  42. package/dist/exceptions/unexpected-response.js +10 -0
  43. package/dist/extensions.d.ts +1 -0
  44. package/dist/extensions.js +10 -4
  45. package/dist/middleware/authenticate.js +5 -15
  46. package/dist/middleware/check-ip.js +9 -6
  47. package/dist/middleware/respond.js +4 -1
  48. package/dist/services/activity.d.ts +2 -1
  49. package/dist/services/activity.js +2 -2
  50. package/dist/services/authentication.d.ts +2 -7
  51. package/dist/services/authentication.js +81 -41
  52. package/dist/services/authorization.js +3 -3
  53. package/dist/services/collections.d.ts +1 -2
  54. package/dist/services/collections.js +2 -2
  55. package/dist/services/files.d.ts +2 -2
  56. package/dist/services/files.js +14 -8
  57. package/dist/services/graphql.js +20 -5
  58. package/dist/services/index.d.ts +1 -0
  59. package/dist/services/index.js +1 -0
  60. package/dist/services/items.d.ts +1 -15
  61. package/dist/services/notifications.d.ts +2 -2
  62. package/dist/services/permissions.d.ts +2 -2
  63. package/dist/services/roles.d.ts +2 -2
  64. package/dist/services/shares.d.ts +17 -0
  65. package/dist/services/shares.js +135 -0
  66. package/dist/services/specifications.js +1 -1
  67. package/dist/services/users.d.ts +2 -2
  68. package/dist/services/users.js +8 -6
  69. package/dist/services/webhooks.d.ts +2 -2
  70. package/dist/tests/database/migrations/run.test.d.ts +1 -0
  71. package/dist/tests/database/migrations/run.test.js +29 -0
  72. package/dist/types/ast.d.ts +3 -3
  73. package/dist/types/auth.d.ts +31 -0
  74. package/dist/types/extensions.d.ts +2 -0
  75. package/dist/types/items.d.ts +14 -0
  76. package/dist/utils/apply-query.d.ts +0 -38
  77. package/dist/utils/apply-query.js +66 -67
  78. package/dist/utils/apply-snapshot.js +69 -14
  79. package/dist/utils/get-ast-from-query.js +3 -3
  80. package/dist/utils/get-default-value.js +3 -1
  81. package/dist/utils/get-permissions.d.ts +2 -2
  82. package/dist/utils/get-permissions.js +117 -72
  83. package/dist/utils/get-relation-type.d.ts +1 -1
  84. package/dist/utils/get-relation-type.js +1 -1
  85. package/dist/utils/merge-permissions-for-share.d.ts +5 -0
  86. package/dist/utils/merge-permissions-for-share.js +116 -0
  87. package/dist/utils/merge-permissions.d.ts +13 -1
  88. package/dist/utils/merge-permissions.js +27 -19
  89. package/dist/utils/reduce-schema.d.ts +2 -2
  90. package/dist/utils/reduce-schema.js +7 -7
  91. package/dist/utils/user-name.js +3 -0
  92. package/example.env +1 -1
  93. package/package.json +14 -13
@@ -62,8 +62,20 @@ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
62
62
  router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
63
63
  router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
64
64
  router.get('/me', (0, async_handler_1.default)(async (req, res, next) => {
65
- var _a;
66
- if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
65
+ var _a, _b, _c;
66
+ if ((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.share_scope) {
67
+ const user = {
68
+ share: (_b = req.accountability) === null || _b === void 0 ? void 0 : _b.share,
69
+ role: {
70
+ id: req.accountability.role,
71
+ admin_access: false,
72
+ app_access: false,
73
+ },
74
+ };
75
+ res.locals.payload = { data: user };
76
+ return next();
77
+ }
78
+ if (!((_c = req.accountability) === null || _c === void 0 ? void 0 : _c.user)) {
67
79
  throw new exceptions_1.InvalidCredentialsException();
68
80
  }
69
81
  const service = new services_1.UsersService({
@@ -108,7 +120,7 @@ router.patch('/me', (0, async_handler_1.default)(async (req, res, next) => {
108
120
  res.locals.payload = { data: item || null };
109
121
  return next();
110
122
  }), respond_1.respond);
111
- router.patch('/me/track/page', (0, async_handler_1.default)(async (req, res, next) => {
123
+ router.patch('/me/track/page', (0, async_handler_1.default)(async (req, _res, next) => {
112
124
  var _a;
113
125
  if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
114
126
  throw new exceptions_1.InvalidCredentialsException();
@@ -162,7 +174,7 @@ router.patch('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
162
174
  }
163
175
  return next();
164
176
  }), respond_1.respond);
165
- router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_handler_1.default)(async (req, res, next) => {
177
+ router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_handler_1.default)(async (req, _res, next) => {
166
178
  const service = new services_1.UsersService({
167
179
  accountability: req.accountability,
168
180
  schema: req.schema,
@@ -178,7 +190,7 @@ router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_hand
178
190
  }
179
191
  return next();
180
192
  }), respond_1.respond);
181
- router.delete('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
193
+ router.delete('/:pk', (0, async_handler_1.default)(async (req, _res, next) => {
182
194
  const service = new services_1.UsersService({
183
195
  accountability: req.accountability,
184
196
  schema: req.schema,
@@ -191,7 +203,7 @@ const inviteSchema = joi_1.default.object({
191
203
  role: joi_1.default.string().uuid({ version: 'uuidv4' }).required(),
192
204
  invite_url: joi_1.default.string().uri(),
193
205
  });
194
- router.post('/invite', (0, async_handler_1.default)(async (req, res, next) => {
206
+ router.post('/invite', (0, async_handler_1.default)(async (req, _res, next) => {
195
207
  const { error } = inviteSchema.validate(req.body);
196
208
  if (error)
197
209
  throw new exceptions_1.InvalidPayloadException(error.message);
@@ -206,7 +218,7 @@ const acceptInviteSchema = joi_1.default.object({
206
218
  token: joi_1.default.string().required(),
207
219
  password: joi_1.default.string().required(),
208
220
  });
209
- router.post('/invite/accept', (0, async_handler_1.default)(async (req, res, next) => {
221
+ router.post('/invite/accept', (0, async_handler_1.default)(async (req, _res, next) => {
210
222
  const { error } = acceptInviteSchema.validate(req.body);
211
223
  if (error)
212
224
  throw new exceptions_1.InvalidPayloadException(error.message);
@@ -238,7 +250,7 @@ router.post('/me/tfa/generate/', (0, async_handler_1.default)(async (req, res, n
238
250
  res.locals.payload = { data: { secret, otpauth_url: url } };
239
251
  return next();
240
252
  }), respond_1.respond);
241
- router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, res, next) => {
253
+ router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, _res, next) => {
242
254
  var _a;
243
255
  if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
244
256
  throw new exceptions_1.InvalidCredentialsException();
@@ -256,7 +268,7 @@ router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, res, nex
256
268
  await service.enableTFA(req.accountability.user, req.body.otp, req.body.secret);
257
269
  return next();
258
270
  }), respond_1.respond);
259
- router.post('/me/tfa/disable', (0, async_handler_1.default)(async (req, res, next) => {
271
+ router.post('/me/tfa/disable', (0, async_handler_1.default)(async (req, _res, next) => {
260
272
  var _a;
261
273
  if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
262
274
  throw new exceptions_1.InvalidCredentialsException();
@@ -0,0 +1,3 @@
1
+ import { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.down = exports.up = void 0;
4
+ async function up(knex) {
5
+ await knex.schema.createTable('directus_shares', (table) => {
6
+ table.uuid('id').primary();
7
+ table.string('name');
8
+ table.string('collection', 64).references('collection').inTable('directus_collections').onDelete('CASCADE');
9
+ table.string('item');
10
+ table.uuid('role').references('id').inTable('directus_roles').onDelete('CASCADE');
11
+ table.string('password');
12
+ table.uuid('user_created').references('id').inTable('directus_users').onDelete('SET NULL');
13
+ table.timestamp('date_created').defaultTo(knex.fn.now());
14
+ // This was changed after the migration went live to retroactively fix mysql5, see #10693
15
+ table.timestamp('date_start').nullable().defaultTo(null);
16
+ table.timestamp('date_end').nullable().defaultTo(null);
17
+ table.integer('times_used').defaultTo(0);
18
+ table.integer('max_uses');
19
+ });
20
+ await knex.schema.alterTable('directus_sessions', (table) => {
21
+ table.dropColumn('data');
22
+ });
23
+ await knex.schema.alterTable('directus_sessions', (table) => {
24
+ table.uuid('user').nullable().alter();
25
+ table.uuid('share').references('id').inTable('directus_shares').onDelete('CASCADE');
26
+ });
27
+ }
28
+ exports.up = up;
29
+ async function down(knex) {
30
+ await knex.schema.alterTable('directus_sessions', (table) => {
31
+ table.uuid('user').notNullable().alter();
32
+ table.json('data');
33
+ table.dropForeign('share');
34
+ table.dropColumn('share');
35
+ });
36
+ await knex.schema.dropTable('directus_shares');
37
+ }
38
+ exports.down = down;
@@ -18,7 +18,7 @@ const helpers_1 = require("../database/helpers");
18
18
  async function runAST(originalAST, schema, options) {
19
19
  const ast = (0, lodash_1.cloneDeep)(originalAST);
20
20
  const knex = (options === null || options === void 0 ? void 0 : options.knex) || (0, _1.default)();
21
- if (ast.type === 'm2a') {
21
+ if (ast.type === 'a2o') {
22
22
  const results = {};
23
23
  for (const collection of ast.names) {
24
24
  results[collection] = await run(collection, ast.children[collection], ast.query[collection]);
@@ -85,7 +85,7 @@ async function parseCurrentLevel(schema, collection, children, query) {
85
85
  if (child.type === 'm2o') {
86
86
  columnsToSelectInternal.push(child.fieldKey);
87
87
  }
88
- if (child.type === 'm2a') {
88
+ if (child.type === 'a2o') {
89
89
  columnsToSelectInternal.push(child.relation.field);
90
90
  columnsToSelectInternal.push(child.relation.meta.one_collection_field);
91
91
  }
@@ -182,7 +182,7 @@ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
182
182
  nestedNode.query.union = [foreignField, foreignIds];
183
183
  }
184
184
  }
185
- else if (nestedNode.type === 'm2a') {
185
+ else if (nestedNode.type === 'a2o') {
186
186
  const keysPerCollection = {};
187
187
  for (const parentItem of parentItems) {
188
188
  const collection = parentItem[nestedNode.relation.meta.one_collection_field];
@@ -256,7 +256,7 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
256
256
  parentItem[nestedNode.fieldKey] = itemChildren.length > 0 ? itemChildren : [];
257
257
  }
258
258
  }
259
- else if (nestedNode.type === 'm2a') {
259
+ else if (nestedNode.type === 'a2o') {
260
260
  for (const parentItem of parentItems) {
261
261
  if (!((_a = nestedNode.relation.meta) === null || _a === void 0 ? void 0 : _a.one_collection_field)) {
262
262
  parentItem[nestedNode.fieldKey] = null;
@@ -279,7 +279,7 @@ function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem
279
279
  var _a;
280
280
  const rawItems = (0, lodash_1.cloneDeep)((0, utils_1.toArray)(rawItem));
281
281
  const items = [];
282
- if (ast.type === 'm2a') {
282
+ if (ast.type === 'a2o') {
283
283
  const fields = {};
284
284
  const nestedCollectionNodes = {};
285
285
  for (const relatedCollection of ast.names) {
@@ -13,18 +13,6 @@
13
13
  comment:
14
14
  _nnull: true
15
15
 
16
- - collection: directus_collections
17
- action: read
18
-
19
- - collection: directus_fields
20
- action: read
21
-
22
- - collection: directus_permissions
23
- action: read
24
- permissions:
25
- role:
26
- _eq: $CURRENT_ROLE
27
-
28
16
  - collection: directus_presets
29
17
  action: read
30
18
  permissions:
@@ -60,9 +48,6 @@
60
48
  user:
61
49
  _eq: $CURRENT_USER
62
50
 
63
- - collection: directus_relations
64
- action: read
65
-
66
51
  - collection: directus_roles
67
52
  action: read
68
53
  permissions:
@@ -1,2 +1,3 @@
1
1
  import { Permission } from '@directus/shared/types';
2
+ export declare const schemaPermissions: Permission[];
2
3
  export declare const appAccessMinimalPermissions: Permission[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.appAccessMinimalPermissions = void 0;
3
+ exports.appAccessMinimalPermissions = exports.schemaPermissions = void 0;
4
4
  const lodash_1 = require("lodash");
5
5
  const require_yaml_1 = require("../../../utils/require-yaml");
6
6
  const defaults = {
@@ -11,5 +11,7 @@ const defaults = {
11
11
  fields: ['*'],
12
12
  system: true,
13
13
  };
14
+ const schemaPermissionsRaw = (0, require_yaml_1.requireYAML)(require.resolve('./schema-access-permissions.yaml'));
14
15
  const permissions = (0, require_yaml_1.requireYAML)(require.resolve('./app-access-permissions.yaml'));
15
- exports.appAccessMinimalPermissions = permissions.map((row) => (0, lodash_1.merge)({}, defaults, row));
16
+ exports.schemaPermissions = schemaPermissionsRaw.map((row) => (0, lodash_1.merge)({}, defaults, row));
17
+ exports.appAccessMinimalPermissions = [...exports.schemaPermissions, ...permissions].map((row) => (0, lodash_1.merge)({}, defaults, row));
@@ -0,0 +1,17 @@
1
+ # NOTE: Activity/collections/fields/presets/relations/revisions will have an extra hardcoded filter
2
+ # to filter out collections you don't have read access
3
+
4
+ - collection: directus_collections
5
+ action: read
6
+
7
+ - collection: directus_fields
8
+ action: read
9
+
10
+ - collection: directus_permissions
11
+ action: read
12
+ permissions:
13
+ role:
14
+ _eq: $CURRENT_ROLE
15
+
16
+ - collection: directus_relations
17
+ action: read
@@ -65,3 +65,6 @@ data:
65
65
  note: $t:directus_collection.directus_panels
66
66
  - collection: directus_notifications
67
67
  note: $t:directus_collection.directus_notifications
68
+ - collection: directus_shares
69
+ icon: share
70
+ note: $t:directus_collection.directus_shares
@@ -12,3 +12,5 @@ width: full
12
12
  group: null
13
13
  translations: null
14
14
  note: null
15
+ conditions: null
16
+ required: false
@@ -11,4 +11,4 @@ fields:
11
11
  width: half
12
12
  - field: user_agent
13
13
  width: half
14
- - field: data
14
+ - field: share
@@ -343,3 +343,12 @@ fields:
343
343
  type:
344
344
  _neq: 'raster'
345
345
  hidden: true
346
+ - field: attribution
347
+ name: $t:fields.directus_settings.attribution
348
+ type: string
349
+ schema:
350
+ is_nullable: true
351
+ meta:
352
+ interface: input
353
+ options:
354
+ placeholder: $t:fields.directus_settings.attribution_placeholder
@@ -0,0 +1,77 @@
1
+ table: directus_shares
2
+
3
+ fields:
4
+ - field: id
5
+ special: uuid
6
+ readonly: true
7
+ hidden: true
8
+
9
+ - field: name
10
+
11
+ - field: collection
12
+ width: half
13
+ hidden: true
14
+
15
+ - field: item
16
+ width: half
17
+ hidden: true
18
+
19
+ - field: role
20
+ interface: select-dropdown-m2o
21
+ width: half
22
+ options:
23
+ template: '{{name}}'
24
+ filter:
25
+ admin_access:
26
+ _eq: false
27
+
28
+ - field: password
29
+ special: hash,conceal
30
+ interface: input-hash
31
+ options:
32
+ iconRight: lock
33
+ masked: true
34
+ width: half
35
+ note: $t:shared_leave_blank_for_unlimited
36
+
37
+ - field: date_start
38
+ width: half
39
+ note: $t:shared_leave_blank_for_unlimited
40
+
41
+ - field: date_end
42
+ width: half
43
+ note: $t:shared_leave_blank_for_unlimited
44
+
45
+ - field: max_uses
46
+ width: half
47
+ note: $t:shared_leave_blank_for_unlimited
48
+
49
+ - field: times_used
50
+ width: half
51
+ readonly: true
52
+
53
+ - field: date_created
54
+ special: date-created
55
+ width: half
56
+ readonly: true
57
+ conditions:
58
+ - name: notCreatedYet
59
+ rule:
60
+ id:
61
+ _null: true
62
+ hidden: true
63
+
64
+ - field: user_created
65
+ special: user-created
66
+ interface: select-dropdown-m2o
67
+ width: half
68
+ display: user
69
+ options:
70
+ template: '{{avatar.$thumbnail}} {{first_name}} {{last_name}}'
71
+ readonly: true
72
+ conditions:
73
+ - name: notCreatedYet
74
+ rule:
75
+ id:
76
+ _null: true
77
+ hidden: true
@@ -100,7 +100,7 @@ fields:
100
100
  options:
101
101
  icon: verified_user
102
102
  title: $t:fields.directus_users.admin_options
103
- color: '#E35169'
103
+ color: 'var(--danger)'
104
104
  special:
105
105
  - alias
106
106
  - no-data
@@ -12,6 +12,9 @@ defaults:
12
12
  sort_field: null
13
13
 
14
14
  data:
15
+ - many_collection: directus_collections
16
+ many_field: group
17
+ one_collection: directus_collections
15
18
  - many_collection: directus_users
16
19
  many_field: role
17
20
  one_collection: directus_roles
@@ -73,6 +76,9 @@ data:
73
76
  - many_collection: directus_sessions
74
77
  many_field: user
75
78
  one_collection: directus_users
79
+ - many_collection: directus_sessions
80
+ many_field: share
81
+ one_collection: directus_shares
76
82
  - many_collection: directus_settings
77
83
  many_field: storage_default_folder
78
84
  one_collection: directus_folders
@@ -88,3 +94,12 @@ data:
88
94
  - many_collection: directus_notifications
89
95
  many_field: sender
90
96
  one_collection: directus_users
97
+ - many_collection: directus_shares
98
+ many_field: role
99
+ one_collection: directus_roles
100
+ - many_collection: directus_shares
101
+ many_field: collection
102
+ one_collection: directus_collections
103
+ - many_collection: directus_shares
104
+ many_field: user_created
105
+ one_collection: directus_users
package/dist/emitter.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import { ActionHandler, FilterHandler, HookContext, InitHandler } from './types';
2
- declare class Emitter {
2
+ export declare class Emitter {
3
3
  private filterEmitter;
4
4
  private actionEmitter;
5
5
  private initEmitter;
6
6
  constructor();
7
- eventsToEmit(event: string, meta: Record<string, any>): string[];
8
7
  emitFilter<T>(event: string, payload: T, meta: Record<string, any>, context: HookContext): Promise<T>;
9
8
  emitAction(event: string, meta: Record<string, any>, context: HookContext): void;
10
9
  emitInit(event: string, meta: Record<string, any>): Promise<void>;
@@ -14,6 +13,8 @@ declare class Emitter {
14
13
  offFilter(event: string, handler: FilterHandler): void;
15
14
  offAction(event: string, handler: ActionHandler): void;
16
15
  offInit(event: string, handler: InitHandler): void;
16
+ offAll(): void;
17
+ private eventsToEmit;
17
18
  }
18
19
  declare const emitter: Emitter;
19
20
  export default emitter;
package/dist/emitter.js CHANGED
@@ -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
+ exports.Emitter = void 0;
6
7
  const eventemitter2_1 = require("eventemitter2");
7
8
  const logger_1 = __importDefault(require("./logger"));
8
9
  class Emitter {
@@ -18,12 +19,6 @@ class Emitter {
18
19
  this.actionEmitter = new eventemitter2_1.EventEmitter2(emitterOptions);
19
20
  this.initEmitter = new eventemitter2_1.EventEmitter2(emitterOptions);
20
21
  }
21
- eventsToEmit(event, meta) {
22
- if (event.startsWith('items')) {
23
- return [event, `${meta.collection}.${event}`];
24
- }
25
- return [event];
26
- }
27
22
  async emitFilter(event, payload, meta, context) {
28
23
  const events = this.eventsToEmit(event, meta);
29
24
  const listeners = events.flatMap((event) => this.filterEmitter.listeners(event));
@@ -72,6 +67,18 @@ class Emitter {
72
67
  offInit(event, handler) {
73
68
  this.initEmitter.off(event, handler);
74
69
  }
70
+ offAll() {
71
+ this.filterEmitter.removeAllListeners();
72
+ this.actionEmitter.removeAllListeners();
73
+ this.initEmitter.removeAllListeners();
74
+ }
75
+ eventsToEmit(event, meta) {
76
+ if (event.startsWith('items')) {
77
+ return [event, `${meta.collection}.${event}`];
78
+ }
79
+ return [event];
80
+ }
75
81
  }
82
+ exports.Emitter = Emitter;
76
83
  const emitter = new Emitter();
77
84
  exports.default = emitter;
package/dist/env.js CHANGED
@@ -20,7 +20,7 @@ const defaults = {
20
20
  PORT: 8055,
21
21
  PUBLIC_URL: '/',
22
22
  MAX_PAYLOAD_SIZE: '100kb',
23
- DB_EXCLUDE_TABLES: 'spatial_ref_sys',
23
+ DB_EXCLUDE_TABLES: 'spatial_ref_sys,sysdiagrams',
24
24
  STORAGE_LOCATIONS: 'local',
25
25
  STORAGE_LOCAL_DRIVER: 'local',
26
26
  STORAGE_LOCAL_ROOT: './uploads',
@@ -15,3 +15,4 @@ export * from './route-not-found';
15
15
  export * from './service-unavailable';
16
16
  export * from './unprocessable-entity';
17
17
  export * from './user-suspended';
18
+ export * from './unexpected-response';
@@ -27,3 +27,4 @@ __exportStar(require("./route-not-found"), exports);
27
27
  __exportStar(require("./service-unavailable"), exports);
28
28
  __exportStar(require("./unprocessable-entity"), exports);
29
29
  __exportStar(require("./user-suspended"), exports);
30
+ __exportStar(require("./unexpected-response"), exports);
@@ -0,0 +1,4 @@
1
+ import { BaseException } from '@directus/shared/exceptions';
2
+ export declare class UnexpectedResponseException extends BaseException {
3
+ constructor(message: string);
4
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnexpectedResponseException = void 0;
4
+ const exceptions_1 = require("@directus/shared/exceptions");
5
+ class UnexpectedResponseException extends exceptions_1.BaseException {
6
+ constructor(message) {
7
+ super(message, 503, 'UNEXPECTED_RESPONSE');
8
+ }
9
+ }
10
+ exports.UnexpectedResponseException = UnexpectedResponseException;
@@ -7,6 +7,7 @@ declare class ExtensionManager {
7
7
  private appExtensions;
8
8
  private apiHooks;
9
9
  private apiEndpoints;
10
+ private apiEmitter;
10
11
  private endpointRouter;
11
12
  private isScheduleHookEnabled;
12
13
  constructor();
@@ -28,7 +28,7 @@ const path_1 = __importDefault(require("path"));
28
28
  const node_1 = require("@directus/shared/utils/node");
29
29
  const constants_1 = require("@directus/shared/constants");
30
30
  const database_1 = __importDefault(require("./database"));
31
- const emitter_1 = __importDefault(require("./emitter"));
31
+ const emitter_1 = __importStar(require("./emitter"));
32
32
  const env_1 = __importDefault(require("./env"));
33
33
  const exceptions = __importStar(require("./exceptions"));
34
34
  const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
@@ -44,6 +44,7 @@ const plugin_virtual_1 = __importDefault(require("@rollup/plugin-virtual"));
44
44
  const plugin_alias_1 = __importDefault(require("@rollup/plugin-alias"));
45
45
  const url_1 = require("./utils/url");
46
46
  const get_module_default_1 = __importDefault(require("./utils/get-module-default"));
47
+ const lodash_1 = require("lodash");
47
48
  let extensionManager;
48
49
  function getExtensionManager() {
49
50
  if (extensionManager) {
@@ -61,6 +62,7 @@ class ExtensionManager {
61
62
  this.apiHooks = [];
62
63
  this.apiEndpoints = [];
63
64
  this.isScheduleHookEnabled = true;
65
+ this.apiEmitter = new emitter_1.Emitter();
64
66
  this.endpointRouter = (0, express_1.Router)();
65
67
  }
66
68
  async initialize({ schedule } = { schedule: true }) {
@@ -92,6 +94,7 @@ class ExtensionManager {
92
94
  logger_1.default.info('Reloading extensions');
93
95
  this.unregisterHooks();
94
96
  this.unregisterEndpoints();
97
+ this.apiEmitter.offAll();
95
98
  if (env_1.default.SERVE_APP) {
96
99
  this.appExtensions = {};
97
100
  }
@@ -139,12 +142,13 @@ class ExtensionManager {
139
142
  return bundles;
140
143
  }
141
144
  async getSharedDepsMapping(deps) {
142
- const appDir = await fs_extra_1.default.readdir(path_1.default.join((0, node_1.resolvePackage)('@directus/app'), 'dist'));
145
+ const appDir = await fs_extra_1.default.readdir(path_1.default.join((0, node_1.resolvePackage)('@directus/app'), 'dist', 'assets'));
143
146
  const depsMapping = {};
144
147
  for (const dep of deps) {
145
- const depName = appDir.find((file) => dep.replace(/\//g, '_') === file.substring(0, file.indexOf('.')));
148
+ const depRegex = new RegExp(`${(0, lodash_1.escapeRegExp)(dep.replace(/\//g, '_'))}\\.[0-9a-f]{8}\\.entry\\.js`);
149
+ const depName = appDir.find((file) => depRegex.test(file));
146
150
  if (depName) {
147
- const depUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', depName);
151
+ const depUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', 'assets', depName);
148
152
  depsMapping[dep] = depUrl.toString({ rootRelative: true });
149
153
  }
150
154
  else {
@@ -237,6 +241,7 @@ class ExtensionManager {
237
241
  exceptions: { ...exceptions, ...sharedExceptions },
238
242
  env: env_1.default,
239
243
  database: (0, database_1.default)(),
244
+ emitter: this.apiEmitter,
240
245
  logger: logger_1.default,
241
246
  getSchema: get_schema_1.getSchema,
242
247
  });
@@ -254,6 +259,7 @@ class ExtensionManager {
254
259
  exceptions: { ...exceptions, ...sharedExceptions },
255
260
  env: env_1.default,
256
261
  database: (0, database_1.default)(),
262
+ emitter: this.apiEmitter,
257
263
  logger: logger_1.default,
258
264
  getSchema: get_schema_1.getSchema,
259
265
  });
@@ -58,22 +58,12 @@ const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
58
58
  throw err;
59
59
  }
60
60
  }
61
- const user = await database
62
- .select('directus_users.role', 'directus_roles.admin_access', 'directus_roles.app_access')
63
- .from('directus_users')
64
- .leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id')
65
- .where({
66
- 'directus_users.id': payload.id,
67
- status: 'active',
68
- })
69
- .first();
70
- if (!user) {
71
- throw new exceptions_1.InvalidCredentialsException();
72
- }
61
+ req.accountability.share = payload.share;
62
+ req.accountability.share_scope = payload.share_scope;
73
63
  req.accountability.user = payload.id;
74
- req.accountability.role = user.role;
75
- req.accountability.admin = user.admin_access === true || user.admin_access == 1;
76
- req.accountability.app = user.app_access === true || user.app_access == 1;
64
+ req.accountability.role = payload.role;
65
+ req.accountability.admin = payload.admin_access === true || payload.admin_access == 1;
66
+ req.accountability.app = payload.app_access === true || payload.app_access == 1;
77
67
  }
78
68
  else {
79
69
  // Try finding the user with the provided token
@@ -7,13 +7,16 @@ exports.checkIP = void 0;
7
7
  const database_1 = __importDefault(require("../database"));
8
8
  const exceptions_1 = require("../exceptions");
9
9
  const async_handler_1 = __importDefault(require("../utils/async-handler"));
10
- exports.checkIP = (0, async_handler_1.default)(async (req, res, next) => {
10
+ exports.checkIP = (0, async_handler_1.default)(async (req, _res, next) => {
11
11
  const database = (0, database_1.default)();
12
- const role = await database
13
- .select('ip_access')
14
- .from('directus_roles')
15
- .where({ id: req.accountability.role })
16
- .first();
12
+ const query = database.select('ip_access').from('directus_roles');
13
+ if (req.accountability.role) {
14
+ query.where({ id: req.accountability.role });
15
+ }
16
+ else {
17
+ query.whereNull('id');
18
+ }
19
+ const role = await query.first();
17
20
  const ipAllowlist = ((role === null || role === void 0 ? void 0 : role.ip_access) || '').split(',').filter((ip) => ip);
18
21
  if (ipAllowlist.length > 0 && ipAllowlist.includes(req.accountability.ip) === false)
19
22
  throw new exceptions_1.InvalidIPException();
@@ -77,9 +77,12 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
77
77
  if (Buffer.isBuffer(res.locals.payload)) {
78
78
  return res.end(res.locals.payload);
79
79
  }
80
- else {
80
+ else if (res.locals.payload) {
81
81
  return res.json(res.locals.payload);
82
82
  }
83
+ else {
84
+ return res.status(204).end();
85
+ }
83
86
  });
84
87
  function getDateFormatted() {
85
88
  const date = new Date();
@@ -1,5 +1,6 @@
1
1
  import { AbstractServiceOptions, PrimaryKey, Item } from '../types';
2
- import { ItemsService, MutationOptions } from './index';
2
+ import { ItemsService } from './items';
3
+ import { MutationOptions } from '../types';
3
4
  import { NotificationsService } from './notifications';
4
5
  import { UsersService } from './users';
5
6
  export declare class ActivityService extends ItemsService {