directus 9.0.1 → 9.2.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.
Files changed (111) hide show
  1. package/dist/app.js +2 -0
  2. package/dist/auth/drivers/ldap.js +9 -13
  3. package/dist/auth/drivers/oauth2.d.ts +1 -1
  4. package/dist/auth/drivers/oauth2.js +2 -2
  5. package/dist/auth/drivers/openid.d.ts +1 -1
  6. package/dist/auth/drivers/openid.js +8 -2
  7. package/dist/auth.js +5 -3
  8. package/dist/cli/commands/database/install.js +2 -4
  9. package/dist/cli/commands/schema/apply.js +26 -10
  10. package/dist/controllers/assets.js +0 -27
  11. package/dist/controllers/auth.js +7 -2
  12. package/dist/controllers/extensions.js +1 -1
  13. package/dist/controllers/notifications.d.ts +2 -0
  14. package/dist/controllers/notifications.js +147 -0
  15. package/dist/database/{functions/types.d.ts → helpers/date/dialects/mssql.d.ts} +2 -1
  16. package/dist/database/{functions → helpers/date}/dialects/mssql.js +4 -6
  17. package/dist/database/{functions → helpers/date}/dialects/mysql.d.ts +2 -4
  18. package/dist/database/{functions → helpers/date}/dialects/mysql.js +4 -6
  19. package/dist/database/{functions/dialects/mssql.d.ts → helpers/date/dialects/oracle.d.ts} +2 -4
  20. package/dist/database/{functions → helpers/date}/dialects/oracle.js +4 -6
  21. package/dist/database/helpers/date/dialects/postgres.d.ts +12 -0
  22. package/dist/database/{functions → helpers/date}/dialects/postgres.js +4 -6
  23. package/dist/database/{functions → helpers/date}/dialects/sqlite.d.ts +3 -4
  24. package/dist/database/helpers/date/dialects/sqlite.js +35 -0
  25. package/dist/database/helpers/date/index.d.ts +6 -0
  26. package/dist/database/helpers/date/index.js +15 -0
  27. package/dist/database/helpers/date/types.d.ts +13 -0
  28. package/dist/database/helpers/date/types.js +10 -0
  29. package/dist/database/helpers/geometry/dialects/mssql.d.ts +14 -0
  30. package/dist/database/helpers/geometry/dialects/mssql.js +36 -0
  31. package/dist/database/helpers/geometry/dialects/mysql.d.ts +7 -0
  32. package/dist/database/helpers/geometry/dialects/mysql.js +16 -0
  33. package/dist/database/helpers/geometry/dialects/oracle.d.ts +15 -0
  34. package/dist/database/helpers/geometry/dialects/oracle.js +39 -0
  35. package/dist/database/helpers/geometry/dialects/postgres.d.ts +10 -0
  36. package/dist/database/helpers/geometry/dialects/postgres.js +23 -0
  37. package/dist/database/helpers/geometry/dialects/redshift.d.ts +7 -0
  38. package/dist/database/helpers/geometry/dialects/redshift.js +16 -0
  39. package/dist/database/helpers/geometry/dialects/sqlite.d.ts +6 -0
  40. package/dist/database/helpers/geometry/dialects/sqlite.js +14 -0
  41. package/dist/database/helpers/geometry/index.d.ts +6 -0
  42. package/dist/database/helpers/geometry/index.js +15 -0
  43. package/dist/database/helpers/{geometry.d.ts → geometry/types.d.ts} +3 -7
  44. package/dist/database/helpers/geometry/types.js +54 -0
  45. package/dist/database/helpers/index.d.ts +8 -0
  46. package/dist/database/helpers/index.js +33 -0
  47. package/dist/database/helpers/types.d.ts +5 -0
  48. package/dist/database/helpers/types.js +9 -0
  49. package/dist/database/index.js +6 -6
  50. package/dist/database/migrations/20211118A-add-notifications.d.ts +3 -0
  51. package/dist/database/migrations/20211118A-add-notifications.js +28 -0
  52. package/dist/database/run-ast.js +5 -5
  53. package/dist/database/seeds/run.js +3 -3
  54. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +14 -0
  55. package/dist/database/system-data/collections/collections.yaml +2 -0
  56. package/dist/database/system-data/fields/notifications.yaml +13 -0
  57. package/dist/database/system-data/fields/users.yaml +5 -0
  58. package/dist/database/system-data/relations/relations.yaml +6 -0
  59. package/dist/env.js +1 -0
  60. package/dist/extensions.js +17 -2
  61. package/dist/middleware/get-permissions.js +3 -102
  62. package/dist/middleware/sanitize-query.js +1 -1
  63. package/dist/services/activity.d.ts +7 -5
  64. package/dist/services/activity.js +87 -3
  65. package/dist/services/assets.js +14 -0
  66. package/dist/services/collections.js +12 -1
  67. package/dist/services/fields.d.ts +2 -0
  68. package/dist/services/fields.js +57 -26
  69. package/dist/services/files.d.ts +1 -1
  70. package/dist/services/files.js +13 -11
  71. package/dist/services/graphql.js +6 -0
  72. package/dist/services/index.d.ts +1 -0
  73. package/dist/services/index.js +1 -0
  74. package/dist/services/items.js +18 -29
  75. package/dist/services/mail/index.js +2 -2
  76. package/dist/services/mail/templates/base.liquid +153 -85
  77. package/dist/services/mail/templates/password-reset.liquid +3 -2
  78. package/dist/services/mail/templates/user-invitation.liquid +4 -4
  79. package/dist/services/notifications.d.ts +12 -0
  80. package/dist/services/notifications.js +41 -0
  81. package/dist/services/payload.d.ts +2 -0
  82. package/dist/services/payload.js +3 -3
  83. package/dist/services/users.js +1 -0
  84. package/dist/types/collection.d.ts +1 -0
  85. package/dist/utils/apply-query.js +9 -11
  86. package/dist/utils/apply-snapshot.js +27 -28
  87. package/dist/utils/get-column.js +2 -2
  88. package/dist/utils/get-default-index-name.js +2 -2
  89. package/dist/utils/get-local-type.js +11 -17
  90. package/dist/utils/get-permissions.d.ts +3 -0
  91. package/dist/utils/get-permissions.js +106 -0
  92. package/dist/utils/md.d.ts +4 -0
  93. package/dist/utils/md.js +15 -0
  94. package/dist/utils/merge-permissions.js +2 -2
  95. package/dist/utils/sanitize-query.js +4 -15
  96. package/dist/utils/user-name.d.ts +2 -0
  97. package/dist/utils/user-name.js +16 -0
  98. package/dist/utils/validate-query.js +1 -1
  99. package/dist/webhooks.js +16 -24
  100. package/package.json +27 -24
  101. package/dist/database/functions/dialects/oracle.d.ts +0 -14
  102. package/dist/database/functions/dialects/postgres.d.ts +0 -14
  103. package/dist/database/functions/dialects/sqlite.js +0 -33
  104. package/dist/database/functions/index.d.ts +0 -3
  105. package/dist/database/functions/index.js +0 -26
  106. package/dist/database/functions/types.js +0 -2
  107. package/dist/database/helpers/date.d.ts +0 -8
  108. package/dist/database/helpers/date.js +0 -44
  109. package/dist/database/helpers/geometry.js +0 -189
  110. package/dist/utils/get-simple-hash.d.ts +0 -5
  111. package/dist/utils/get-simple-hash.js +0 -15
@@ -36,14 +36,13 @@ async function applySnapshot(snapshot, options) {
36
36
  // edits
37
37
  snapshotDiff.fields = snapshotDiff.fields.filter((fieldDiff) => fieldDiff.collection !== collection);
38
38
  }
39
- if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E') {
40
- const updates = diff.reduce((acc, edit) => {
41
- if (edit.kind !== 'E')
42
- return acc;
43
- (0, lodash_1.set)(acc, edit.path, edit.rhs);
44
- return acc;
45
- }, {});
46
- await collectionsService.updateOne(collection, updates);
39
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
40
+ const newValues = snapshot.collections.find((field) => {
41
+ return field.collection === collection;
42
+ });
43
+ if (newValues) {
44
+ await collectionsService.updateOne(collection, newValues);
45
+ }
47
46
  }
48
47
  }
49
48
  const fieldsService = new services_1.FieldsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
@@ -51,18 +50,15 @@ async function applySnapshot(snapshot, options) {
51
50
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
52
51
  await fieldsService.createField(collection, diff[0].rhs);
53
52
  }
54
- if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E') {
55
- const updates = diff.reduce((acc, edit) => {
56
- if (edit.kind !== 'E')
57
- return acc;
58
- (0, lodash_1.set)(acc, edit.path, edit.rhs);
59
- return acc;
60
- }, {});
61
- await fieldsService.updateField(collection, {
62
- field,
63
- type: 'unknown',
64
- ...updates,
53
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
54
+ const newValues = snapshot.fields.find((snapshotField) => {
55
+ return snapshotField.collection === collection && snapshotField.field === field;
65
56
  });
57
+ if (newValues) {
58
+ await fieldsService.updateField(collection, {
59
+ ...newValues,
60
+ });
61
+ }
66
62
  }
67
63
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
68
64
  await fieldsService.deleteField(collection, field);
@@ -72,18 +68,21 @@ async function applySnapshot(snapshot, options) {
72
68
  }
73
69
  }
74
70
  const relationsService = new services_1.RelationsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
75
- for (const { collection, field, diff, related_collection } of snapshotDiff.relations) {
71
+ for (const { collection, field, diff } of snapshotDiff.relations) {
72
+ const structure = {};
73
+ for (const diffEdit of diff) {
74
+ (0, lodash_1.set)(structure, diffEdit.path, undefined);
75
+ }
76
76
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
77
77
  await relationsService.createOne(diff[0].rhs);
78
78
  }
79
- if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E') {
80
- const updates = diff.reduce((acc, edit) => {
81
- if (edit.kind !== 'E')
82
- return acc;
83
- (0, lodash_1.set)(acc, edit.path, edit.rhs);
84
- return acc;
85
- }, { collection, field, related_collection });
86
- await relationsService.updateOne(collection, field, updates);
79
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
80
+ const newValues = snapshot.relations.find((relation) => {
81
+ return relation.collection === collection && relation.field === field;
82
+ });
83
+ if (newValues) {
84
+ await relationsService.updateOne(collection, field, newValues);
85
+ }
87
86
  }
88
87
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
89
88
  await relationsService.deleteOne(collection, field);
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getColumn = void 0;
4
- const functions_1 = require("../database/functions");
4
+ const helpers_1 = require("../database/helpers");
5
5
  const constants_1 = require("@directus/shared/constants");
6
6
  const apply_function_to_column_name_1 = require("./apply-function-to-column-name");
7
7
  /**
@@ -15,7 +15,7 @@ const apply_function_to_column_name_1 = require("./apply-function-to-column-name
15
15
  * @returns Knex raw instance
16
16
  */
17
17
  function getColumn(knex, table, column, alias = (0, apply_function_to_column_name_1.applyFunctionToColumnName)(column)) {
18
- const fn = (0, functions_1.FunctionsHelper)(knex);
18
+ const { date: fn } = (0, helpers_1.getHelpers)(knex);
19
19
  if (column.includes('(') && column.includes(')')) {
20
20
  const functionName = column.split('(')[0];
21
21
  const columnName = column.match(constants_1.REGEX_BETWEEN_PARENS)[1];
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDefaultIndexName = void 0;
4
- const get_simple_hash_1 = require("./get-simple-hash");
4
+ const utils_1 = require("@directus/shared/utils");
5
5
  /**
6
6
  * Generate an index name for a given collection + fields combination.
7
7
  *
@@ -18,7 +18,7 @@ function getDefaultIndexName(type, collection, fields) {
18
18
  const indexName = (table + '_' + fields.join('_') + '_' + type).toLowerCase();
19
19
  if (indexName.length <= 60)
20
20
  return indexName;
21
- const suffix = `__${(0, get_simple_hash_1.simpleHash)(indexName)}_${type}`;
21
+ const suffix = `__${(0, utils_1.getSimpleHash)(indexName)}_${type}`;
22
22
  const prefix = indexName.substring(0, 60 - suffix.length);
23
23
  return `${prefix}${suffix}`;
24
24
  }
@@ -1,10 +1,5 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const database_1 = require("../database");
7
- const database_2 = __importDefault(require("../database"));
8
3
  const localTypeMap = {
9
4
  // Shared
10
5
  boolean: 'boolean',
@@ -53,8 +48,10 @@ const localTypeMap = {
53
48
  blob: 'binary',
54
49
  mediumblob: 'binary',
55
50
  'int unsigned': 'integer',
56
- 'tinyint(0)': 'boolean',
57
- 'tinyint(1)': 'boolean',
51
+ 'tinyint unsigned': 'integer',
52
+ 'smallint unsigned': 'integer',
53
+ 'mediumint unsigned': 'integer',
54
+ 'bigint unsigned': 'integer',
58
55
  // MS SQL
59
56
  bit: 'boolean',
60
57
  smallmoney: 'float',
@@ -98,9 +95,10 @@ const localTypeMap = {
98
95
  integerfirst: 'integer',
99
96
  };
100
97
  function getLocalType(column, field) {
101
- const database = (0, database_2.default)();
102
- const databaseClient = (0, database_1.getDatabaseClient)(database);
103
- const type = column ? localTypeMap[column.data_type.toLowerCase().split('(')[0]] : 'alias';
98
+ if (!column)
99
+ return 'alias';
100
+ const dataType = column.data_type.toLowerCase();
101
+ const type = localTypeMap[dataType.split('(')[0]];
104
102
  const special = field === null || field === void 0 ? void 0 : field.special;
105
103
  if (special) {
106
104
  if (special.includes('json'))
@@ -111,22 +109,18 @@ function getLocalType(column, field) {
111
109
  return 'csv';
112
110
  if (special.includes('uuid'))
113
111
  return 'uuid';
114
- if (type.startsWith('geometry')) {
112
+ if (type === null || type === void 0 ? void 0 : type.startsWith('geometry')) {
115
113
  return special[0] || 'geometry';
116
114
  }
117
115
  }
118
116
  /** Handle Postgres numeric decimals */
119
- if (column && column.data_type === 'numeric' && column.numeric_precision !== null && column.numeric_scale !== null) {
117
+ if (dataType === 'numeric' && column.numeric_precision !== null && column.numeric_scale !== null) {
120
118
  return 'decimal';
121
119
  }
122
120
  /** Handle MS SQL varchar(MAX) (eg TEXT) types */
123
- if (column && column.data_type === 'nvarchar' && column.max_length === -1) {
121
+ if (column.data_type === 'nvarchar' && column.max_length === -1) {
124
122
  return 'text';
125
123
  }
126
- /** Handle Boolean as TINYINT and edgecase MySQL where it still is just tinyint */
127
- if (column && databaseClient === 'mysql' && column.data_type.toLowerCase() === 'tinyint') {
128
- return 'boolean';
129
- }
130
124
  return type !== null && type !== void 0 ? type : 'unknown';
131
125
  }
132
126
  exports.default = getLocalType;
@@ -0,0 +1,3 @@
1
+ import { Accountability } from '@directus/shared/types';
2
+ import { SchemaOverview } from '../types';
3
+ export declare function getPermissions(accountability: Accountability, schema: SchemaOverview): Promise<any>;
@@ -0,0 +1,106 @@
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.getPermissions = void 0;
7
+ const utils_1 = require("@directus/shared/utils");
8
+ const lodash_1 = require("lodash");
9
+ const database_1 = __importDefault(require("../database"));
10
+ const app_access_permissions_1 = require("../database/system-data/app-access-permissions");
11
+ const merge_permissions_1 = require("../utils/merge-permissions");
12
+ const users_1 = require("../services/users");
13
+ const roles_1 = require("../services/roles");
14
+ const cache_1 = require("../cache");
15
+ const object_hash_1 = __importDefault(require("object-hash"));
16
+ const env_1 = __importDefault(require("../env"));
17
+ async function getPermissions(accountability, schema) {
18
+ const database = (0, database_1.default)();
19
+ const { systemCache } = (0, cache_1.getCache)();
20
+ let permissions = [];
21
+ const { user, role, app, admin } = accountability;
22
+ const cacheKey = `permissions-${(0, object_hash_1.default)({ user, role, app, admin })}`;
23
+ if (env_1.default.CACHE_PERMISSIONS !== false) {
24
+ const cachedPermissions = await systemCache.get(cacheKey);
25
+ if (cachedPermissions) {
26
+ return cachedPermissions;
27
+ }
28
+ }
29
+ if (accountability.admin !== true) {
30
+ const permissionsForRole = await database
31
+ .select('*')
32
+ .from('directus_permissions')
33
+ .where({ role: accountability.role });
34
+ const requiredPermissionData = {
35
+ $CURRENT_USER: [],
36
+ $CURRENT_ROLE: [],
37
+ };
38
+ permissions = permissionsForRole.map((permissionRaw) => {
39
+ const permission = (0, lodash_1.cloneDeep)(permissionRaw);
40
+ if (permission.permissions && typeof permission.permissions === 'string') {
41
+ permission.permissions = JSON.parse(permission.permissions);
42
+ }
43
+ else if (permission.permissions === null) {
44
+ permission.permissions = {};
45
+ }
46
+ if (permission.validation && typeof permission.validation === 'string') {
47
+ permission.validation = JSON.parse(permission.validation);
48
+ }
49
+ else if (permission.validation === null) {
50
+ permission.validation = {};
51
+ }
52
+ if (permission.presets && typeof permission.presets === 'string') {
53
+ permission.presets = JSON.parse(permission.presets);
54
+ }
55
+ else if (permission.presets === null) {
56
+ permission.presets = {};
57
+ }
58
+ if (permission.fields && typeof permission.fields === 'string') {
59
+ permission.fields = permission.fields.split(',');
60
+ }
61
+ else if (permission.fields === null) {
62
+ permission.fields = [];
63
+ }
64
+ const extractPermissionData = (val) => {
65
+ if (typeof val === 'string' && val.startsWith('$CURRENT_USER.')) {
66
+ requiredPermissionData.$CURRENT_USER.push(val.replace('$CURRENT_USER.', ''));
67
+ }
68
+ if (typeof val === 'string' && val.startsWith('$CURRENT_ROLE.')) {
69
+ requiredPermissionData.$CURRENT_ROLE.push(val.replace('$CURRENT_ROLE.', ''));
70
+ }
71
+ return val;
72
+ };
73
+ (0, utils_1.deepMap)(permission.permissions, extractPermissionData);
74
+ (0, utils_1.deepMap)(permission.validation, extractPermissionData);
75
+ (0, utils_1.deepMap)(permission.presets, extractPermissionData);
76
+ return permission;
77
+ });
78
+ if (accountability.app === true) {
79
+ permissions = (0, merge_permissions_1.mergePermissions)(permissions, app_access_permissions_1.appAccessMinimalPermissions.map((perm) => ({ ...perm, role: accountability.role })));
80
+ }
81
+ const usersService = new users_1.UsersService({ schema });
82
+ const rolesService = new roles_1.RolesService({ schema });
83
+ const filterContext = {};
84
+ if (accountability.user && requiredPermissionData.$CURRENT_USER.length > 0) {
85
+ filterContext.$CURRENT_USER = await usersService.readOne(accountability.user, {
86
+ fields: requiredPermissionData.$CURRENT_USER,
87
+ });
88
+ }
89
+ if (accountability.role && requiredPermissionData.$CURRENT_ROLE.length > 0) {
90
+ filterContext.$CURRENT_ROLE = await rolesService.readOne(accountability.role, {
91
+ fields: requiredPermissionData.$CURRENT_ROLE,
92
+ });
93
+ }
94
+ permissions = permissions.map((permission) => {
95
+ permission.permissions = (0, utils_1.parseFilter)(permission.permissions, accountability, filterContext);
96
+ permission.validation = (0, utils_1.parseFilter)(permission.validation, accountability, filterContext);
97
+ permission.presets = (0, utils_1.parseFilter)(permission.presets, accountability, filterContext);
98
+ return permission;
99
+ });
100
+ if (env_1.default.CACHE_PERMISSIONS !== false) {
101
+ await systemCache.set(cacheKey, permissions);
102
+ }
103
+ }
104
+ return permissions;
105
+ }
106
+ exports.getPermissions = getPermissions;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Render and sanitize a markdown string
3
+ */
4
+ export declare function md(str: string): string;
@@ -0,0 +1,15 @@
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.md = void 0;
7
+ const marked_1 = require("marked");
8
+ const sanitize_html_1 = __importDefault(require("sanitize-html"));
9
+ /**
10
+ * Render and sanitize a markdown string
11
+ */
12
+ function md(str) {
13
+ return (0, sanitize_html_1.default)((0, marked_1.parse)(str));
14
+ }
15
+ exports.md = md;
@@ -23,13 +23,13 @@ function mergePerm(currentPerm, newPerm) {
23
23
  let validation = currentPerm.validation;
24
24
  let fields = currentPerm.fields;
25
25
  let presets = currentPerm.presets;
26
- if (newPerm.permissions) {
26
+ if (newPerm.permissions && !(0, lodash_1.isEmpty)(newPerm.permissions)) {
27
27
  if (currentPerm.permissions && Object.keys(currentPerm.permissions)[0] === '_or') {
28
28
  permissions = {
29
29
  _or: [...currentPerm.permissions._or, newPerm.permissions],
30
30
  };
31
31
  }
32
- else if (currentPerm.permissions) {
32
+ else if (currentPerm.permissions && !(0, lodash_1.isEmpty)(currentPerm.permissions)) {
33
33
  permissions = {
34
34
  _or: [currentPerm.permissions, newPerm.permissions],
35
35
  };
@@ -106,19 +106,7 @@ function sanitizeFilter(rawFilter, accountability) {
106
106
  logger_1.default.warn('Invalid value passed for filter query parameter.');
107
107
  }
108
108
  }
109
- filters = (0, utils_1.deepMap)(filters, (val) => {
110
- try {
111
- const parsed = JSON.parse(val);
112
- if (typeof parsed == 'number' && !Number.isSafeInteger(parsed))
113
- return val;
114
- return parsed;
115
- }
116
- catch {
117
- return val;
118
- }
119
- });
120
- filters = (0, utils_1.parseFilter)(filters, accountability);
121
- return filters;
109
+ return (0, utils_1.parseFilter)(filters, accountability);
122
110
  }
123
111
  function sanitizeLimit(rawLimit) {
124
112
  if (rawLimit === undefined || rawLimit === null)
@@ -165,9 +153,10 @@ function sanitizeDeep(deep, accountability) {
165
153
  const parsedSubQuery = sanitizeQuery({ [key.substring(1)]: value }, accountability);
166
154
  // ...however we want to keep them for the nested structure of deep, otherwise there's no
167
155
  // way of knowing when to keep nesting and when to stop
168
- parsedLevel[key] = Object.values(parsedSubQuery)[0];
156
+ const [parsedKey, parsedValue] = Object.entries(parsedSubQuery)[0];
157
+ parsedLevel[`_${parsedKey}`] = parsedValue;
169
158
  }
170
- else {
159
+ else if ((0, lodash_1.isPlainObject)(value)) {
171
160
  parse(value, [...path, key]);
172
161
  }
173
162
  }
@@ -0,0 +1,2 @@
1
+ import { User } from '@directus/shared/types';
2
+ export declare function userName(user: Partial<User>): string;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.userName = void 0;
4
+ function userName(user) {
5
+ if (user.first_name && user.last_name) {
6
+ return `${user.first_name} ${user.last_name}`;
7
+ }
8
+ if (user.first_name) {
9
+ return user.first_name;
10
+ }
11
+ if (user.email) {
12
+ return user.email;
13
+ }
14
+ return 'Unknown User';
15
+ }
16
+ exports.userName = userName;
@@ -100,7 +100,7 @@ function validateFilterPrimitive(value, key) {
100
100
  false) {
101
101
  throw new exceptions_1.InvalidQueryException(`The filter value for "${key}" has to be a string, number, or boolean`);
102
102
  }
103
- if (typeof value === 'number' && Number.isNaN(value)) {
103
+ if (typeof value === 'number' && (Number.isNaN(value) || !Number.isSafeInteger(value))) {
104
104
  throw new exceptions_1.InvalidQueryException(`The filter value for "${key}" is not a valid number`);
105
105
  }
106
106
  if (typeof value === 'string' && value.length === 0) {
package/dist/webhooks.js CHANGED
@@ -8,7 +8,6 @@ const axios_1 = __importDefault(require("axios"));
8
8
  const database_1 = __importDefault(require("./database"));
9
9
  const emitter_1 = __importDefault(require("./emitter"));
10
10
  const logger_1 = __importDefault(require("./logger"));
11
- const lodash_1 = require("lodash");
12
11
  const services_1 = require("./services");
13
12
  const get_schema_1 = require("./utils/get-schema");
14
13
  let registered = [];
@@ -17,20 +16,12 @@ async function register() {
17
16
  const webhookService = new services_1.WebhooksService({ knex: (0, database_1.default)(), schema: await (0, get_schema_1.getSchema)() });
18
17
  const webhooks = await webhookService.readByQuery({ filter: { status: { _eq: 'active' } } });
19
18
  for (const webhook of webhooks) {
20
- if (webhook.actions.includes('*')) {
21
- const event = 'items.*';
22
- const handler = createHandler(webhook);
19
+ for (const action of webhook.actions) {
20
+ const event = `items.${action}`;
21
+ const handler = createHandler(webhook, event);
23
22
  emitter_1.default.onAction(event, handler);
24
23
  registered.push({ event, handler });
25
24
  }
26
- else {
27
- for (const action of webhook.actions) {
28
- const event = `items.${action}`;
29
- const handler = createHandler(webhook);
30
- emitter_1.default.onAction(event, handler);
31
- registered.push({ event, handler });
32
- }
33
- }
34
25
  }
35
26
  }
36
27
  exports.register = register;
@@ -41,19 +32,20 @@ function unregister() {
41
32
  registered = [];
42
33
  }
43
34
  exports.unregister = unregister;
44
- function createHandler(webhook) {
45
- return async (data) => {
46
- if (webhook.collections.includes('*') === false && webhook.collections.includes(data.collection) === false)
35
+ function createHandler(webhook, event) {
36
+ return async (meta, context) => {
37
+ if (webhook.collections.includes(meta.collection) === false)
47
38
  return;
48
- const webhookPayload = (0, lodash_1.pick)(data, [
49
- 'event',
50
- 'accountability.user',
51
- 'accountability.role',
52
- 'collection',
53
- 'item',
54
- 'action',
55
- 'payload',
56
- ]);
39
+ const webhookPayload = {
40
+ event,
41
+ accountability: context.accountability
42
+ ? {
43
+ user: context.accountability.user,
44
+ role: context.accountability.role,
45
+ }
46
+ : null,
47
+ ...meta,
48
+ };
57
49
  try {
58
50
  await (0, axios_1.default)({
59
51
  url: webhook.url,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "directus",
3
- "version": "9.0.1",
3
+ "version": "9.2.0",
4
4
  "license": "GPL-3.0-only",
5
5
  "homepage": "https://github.com/directus/directus#readme",
6
6
  "description": "Directus is a real-time API and App dashboard for managing SQL database content.",
@@ -76,16 +76,16 @@
76
76
  ],
77
77
  "dependencies": {
78
78
  "@aws-sdk/client-ses": "^3.40.0",
79
- "@directus/app": "9.0.1",
80
- "@directus/drive": "9.0.1",
81
- "@directus/drive-azure": "9.0.1",
82
- "@directus/drive-gcs": "9.0.1",
83
- "@directus/drive-s3": "9.0.1",
84
- "@directus/extensions-sdk": "9.0.1",
85
- "@directus/format-title": "9.0.1",
86
- "@directus/schema": "9.0.1",
87
- "@directus/shared": "9.0.1",
88
- "@directus/specs": "9.0.1",
79
+ "@directus/app": "9.2.0",
80
+ "@directus/drive": "9.2.0",
81
+ "@directus/drive-azure": "9.2.0",
82
+ "@directus/drive-gcs": "9.2.0",
83
+ "@directus/drive-s3": "9.2.0",
84
+ "@directus/extensions-sdk": "9.2.0",
85
+ "@directus/format-title": "9.2.0",
86
+ "@directus/schema": "9.2.0",
87
+ "@directus/shared": "9.2.0",
88
+ "@directus/specs": "9.2.0",
89
89
  "@godaddy/terminus": "^4.9.0",
90
90
  "@rollup/plugin-alias": "^3.1.2",
91
91
  "@rollup/plugin-virtual": "^2.0.3",
@@ -122,11 +122,12 @@
122
122
  "jsonwebtoken": "^8.5.1",
123
123
  "keyv": "^4.0.3",
124
124
  "knex": "^0.95.11",
125
- "knex-schema-inspector": "1.6.4",
125
+ "knex-schema-inspector": "1.6.6",
126
126
  "ldapjs": "^2.3.1",
127
127
  "liquidjs": "^9.25.0",
128
128
  "lodash": "^4.17.21",
129
129
  "macos-release": "^2.4.1",
130
+ "marked": "^4.0.3",
130
131
  "mime-types": "^2.1.31",
131
132
  "ms": "^2.1.3",
132
133
  "nanoid": "^3.1.23",
@@ -145,6 +146,7 @@
145
146
  "rate-limiter-flexible": "^2.2.2",
146
147
  "resolve-cwd": "^3.0.0",
147
148
  "rollup": "^2.52.1",
149
+ "sanitize-html": "^2.6.0",
148
150
  "sharp": "^0.29.0",
149
151
  "stream-json": "^1.7.1",
150
152
  "supertest": "^6.1.6",
@@ -167,40 +169,41 @@
167
169
  "sqlite3": "^5.0.2",
168
170
  "tedious": "^13.0.0"
169
171
  },
170
- "gitHead": "ba72d2cfd040f7f0db282ccac006f36df6f05058",
172
+ "gitHead": "776c105aacfda559a1ebf49cb2220599652f6c48",
171
173
  "devDependencies": {
172
- "@types/async": "3.2.9",
174
+ "@types/async": "3.2.10",
173
175
  "@types/atob": "2.1.2",
174
- "@types/body-parser": "1.19.1",
176
+ "@types/body-parser": "1.19.2",
175
177
  "@types/busboy": "0.3.1",
176
178
  "@types/cookie-parser": "1.4.2",
177
179
  "@types/cors": "2.8.12",
178
180
  "@types/deep-diff": "1.0.1",
179
181
  "@types/destroy": "1.0.0",
180
182
  "@types/express": "4.17.13",
181
- "@types/express-pino-logger": "4.0.2",
183
+ "@types/express-pino-logger": "4.0.3",
182
184
  "@types/express-session": "1.17.4",
183
185
  "@types/flat": "5.0.2",
184
186
  "@types/fs-extra": "9.0.13",
185
187
  "@types/inquirer": "8.1.3",
186
- "@types/jest": "27.0.2",
187
- "@types/js-yaml": "4.0.4",
188
+ "@types/jest": "27.0.3",
189
+ "@types/js-yaml": "4.0.5",
188
190
  "@types/json2csv": "5.0.3",
189
- "@types/jsonwebtoken": "8.5.5",
191
+ "@types/jsonwebtoken": "8.5.6",
190
192
  "@types/keyv": "3.1.3",
191
193
  "@types/ldapjs": "2.2.2",
192
- "@types/lodash": "4.14.176",
194
+ "@types/lodash": "4.14.177",
193
195
  "@types/mime-types": "2.1.1",
194
196
  "@types/ms": "0.7.31",
195
- "@types/node": "16.11.7",
197
+ "@types/node": "16.11.9",
196
198
  "@types/node-cron": "2.0.5",
197
199
  "@types/nodemailer": "6.4.4",
198
200
  "@types/object-hash": "2.2.1",
199
201
  "@types/qs": "6.9.7",
200
- "@types/sharp": "0.29.3",
202
+ "@types/sanitize-html": "^2.5.0",
203
+ "@types/sharp": "0.29.4",
201
204
  "@types/stream-json": "1.7.1",
202
205
  "@types/supertest": "2.0.11",
203
- "@types/uuid": "8.3.1",
206
+ "@types/uuid": "8.3.3",
204
207
  "@types/uuid-validate": "0.0.1",
205
208
  "@types/wellknown": "0.5.1",
206
209
  "copyfiles": "2.4.1",
@@ -208,6 +211,6 @@
208
211
  "jest": "27.3.1",
209
212
  "ts-jest": "27.0.7",
210
213
  "ts-node-dev": "1.1.8",
211
- "typescript": "4.4.4"
214
+ "typescript": "4.5.2"
212
215
  }
213
216
  }
@@ -1,14 +0,0 @@
1
- import { Knex } from 'knex';
2
- import { HelperFn } from '../types';
3
- export declare class HelperOracle implements HelperFn {
4
- private knex;
5
- constructor(knex: Knex);
6
- year(table: string, column: string): Knex.Raw;
7
- month(table: string, column: string): Knex.Raw;
8
- week(table: string, column: string): Knex.Raw;
9
- day(table: string, column: string): Knex.Raw;
10
- weekday(table: string, column: string): Knex.Raw;
11
- hour(table: string, column: string): Knex.Raw;
12
- minute(table: string, column: string): Knex.Raw;
13
- second(table: string, column: string): Knex.Raw;
14
- }
@@ -1,14 +0,0 @@
1
- import { Knex } from 'knex';
2
- import { HelperFn } from '../types';
3
- export declare class HelperPostgres implements HelperFn {
4
- private knex;
5
- constructor(knex: Knex);
6
- year(table: string, column: string): Knex.Raw;
7
- month(table: string, column: string): Knex.Raw;
8
- week(table: string, column: string): Knex.Raw;
9
- day(table: string, column: string): Knex.Raw;
10
- weekday(table: string, column: string): Knex.Raw;
11
- hour(table: string, column: string): Knex.Raw;
12
- minute(table: string, column: string): Knex.Raw;
13
- second(table: string, column: string): Knex.Raw;
14
- }
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HelperSQLite = void 0;
4
- class HelperSQLite {
5
- constructor(knex) {
6
- this.knex = knex;
7
- }
8
- year(table, column) {
9
- return this.knex.raw("strftime('%Y', ??.??)", [table, column]);
10
- }
11
- month(table, column) {
12
- return this.knex.raw("strftime('%m', ??.??)", [table, column]);
13
- }
14
- week(table, column) {
15
- return this.knex.raw("strftime('%W', ??.??)", [table, column]);
16
- }
17
- day(table, column) {
18
- return this.knex.raw("strftime('%d', ??.??)", [table, column]);
19
- }
20
- weekday(table, column) {
21
- return this.knex.raw("strftime('%w', ??.??)", [table, column]);
22
- }
23
- hour(table, column) {
24
- return this.knex.raw("strftime('%H', ??.??)", [table, column]);
25
- }
26
- minute(table, column) {
27
- return this.knex.raw("strftime('%M', ??.??)", [table, column]);
28
- }
29
- second(table, column) {
30
- return this.knex.raw("strftime('%S', ??.??)", [table, column]);
31
- }
32
- }
33
- exports.HelperSQLite = HelperSQLite;
@@ -1,3 +0,0 @@
1
- import { Knex } from 'knex';
2
- import { HelperFn } from './types';
3
- export declare function FunctionsHelper(knex: Knex): HelperFn;