directus 9.7.1 → 9.8.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 (59) hide show
  1. package/dist/cache.js +2 -2
  2. package/dist/database/helpers/date/dialects/default.d.ts +3 -0
  3. package/dist/database/helpers/date/dialects/default.js +7 -0
  4. package/dist/database/helpers/date/dialects/sqlite.d.ts +0 -9
  5. package/dist/database/helpers/date/dialects/sqlite.js +0 -24
  6. package/dist/database/helpers/date/index.d.ts +6 -6
  7. package/dist/database/helpers/date/index.js +13 -13
  8. package/dist/database/helpers/date/types.d.ts +0 -9
  9. package/dist/database/helpers/{date → fn}/dialects/mssql.d.ts +3 -2
  10. package/dist/database/helpers/{date → fn}/dialects/mssql.js +14 -3
  11. package/dist/database/helpers/{date → fn}/dialects/mysql.d.ts +3 -2
  12. package/dist/database/helpers/{date → fn}/dialects/mysql.js +14 -3
  13. package/dist/database/helpers/{date → fn}/dialects/oracle.d.ts +3 -2
  14. package/dist/database/helpers/{date → fn}/dialects/oracle.js +14 -3
  15. package/dist/database/helpers/{date → fn}/dialects/postgres.d.ts +3 -2
  16. package/dist/database/helpers/{date → fn}/dialects/postgres.js +14 -3
  17. package/dist/database/helpers/fn/dialects/sqlite.d.ts +13 -0
  18. package/dist/database/helpers/fn/dialects/sqlite.js +42 -0
  19. package/dist/database/helpers/fn/index.d.ts +7 -0
  20. package/dist/database/helpers/fn/index.js +17 -0
  21. package/dist/database/helpers/fn/types.d.ts +18 -0
  22. package/dist/database/helpers/fn/types.js +27 -0
  23. package/dist/database/helpers/index.d.ts +4 -1
  24. package/dist/database/helpers/index.js +7 -1
  25. package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.d.ts +3 -0
  26. package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.js +17 -0
  27. package/dist/database/migrations/20220322A-rename-field-typecast-flags.js +6 -2
  28. package/dist/database/migrations/20220323A-add-field-validation.d.ts +3 -0
  29. package/dist/database/migrations/20220323A-add-field-validation.js +17 -0
  30. package/dist/database/migrations/20220325A-fix-typecast-flags.d.ts +3 -0
  31. package/dist/database/migrations/20220325A-fix-typecast-flags.js +49 -0
  32. package/dist/database/migrations/20220325B-add-default-language.d.ts +3 -0
  33. package/dist/database/migrations/20220325B-add-default-language.js +28 -0
  34. package/dist/database/run-ast.js +4 -2
  35. package/dist/database/system-data/fields/activity.yaml +4 -4
  36. package/dist/database/system-data/fields/fields.yaml +9 -0
  37. package/dist/database/system-data/fields/presets.yaml +14 -0
  38. package/dist/database/system-data/fields/settings.yaml +13 -1
  39. package/dist/logger.js +2 -1
  40. package/dist/services/activity.js +4 -1
  41. package/dist/services/authorization.d.ts +1 -1
  42. package/dist/services/authorization.js +128 -44
  43. package/dist/services/collections.js +222 -198
  44. package/dist/services/fields.js +184 -173
  45. package/dist/services/payload.js +8 -6
  46. package/dist/services/relations.js +93 -81
  47. package/dist/services/server.js +1 -0
  48. package/dist/services/shares.js +2 -1
  49. package/dist/services/users.js +3 -1
  50. package/dist/utils/apply-query.js +21 -3
  51. package/dist/utils/get-column.d.ts +6 -5
  52. package/dist/utils/get-column.js +16 -8
  53. package/dist/utils/get-schema.d.ts +1 -1
  54. package/dist/utils/get-schema.js +15 -10
  55. package/dist/utils/track.js +3 -2
  56. package/dist/utils/url.d.ts +1 -1
  57. package/dist/utils/url.js +1 -1
  58. package/dist/utils/validate-storage.js +3 -1
  59. package/package.json +12 -12
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.down = exports.up = void 0;
4
+ const helpers_1 = require("../helpers");
5
+ async function up(knex) {
6
+ const helper = (0, helpers_1.getHelpers)(knex).schema;
7
+ await knex.schema.alterTable('directus_settings', (table) => {
8
+ table.string('default_language').notNullable().defaultTo('en-US');
9
+ });
10
+ await helper.changeToString('directus_users', 'language', {
11
+ nullable: true,
12
+ default: null,
13
+ length: 255,
14
+ });
15
+ }
16
+ exports.up = up;
17
+ async function down(knex) {
18
+ const helper = (0, helpers_1.getHelpers)(knex).schema;
19
+ await knex.schema.alterTable('directus_settings', (table) => {
20
+ table.dropColumn('default_language');
21
+ });
22
+ await helper.changeToString('directus_users', 'language', {
23
+ nullable: true,
24
+ default: 'en-US',
25
+ length: 255,
26
+ });
27
+ }
28
+ exports.down = down;
@@ -151,7 +151,7 @@ function getColumnPreprocessor(knex, schema, table) {
151
151
  if (field.type.startsWith('geometry')) {
152
152
  return helpers.st.asText(table, field.field);
153
153
  }
154
- return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias);
154
+ return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema);
155
155
  };
156
156
  }
157
157
  function getDBQuery(schema, knex, table, fieldNodes, query) {
@@ -244,7 +244,9 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
244
244
  if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
245
245
  parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
246
246
  }
247
- parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, (_a = nestedNode.query.limit) !== null && _a !== void 0 ? _a : 100);
247
+ if (nestedNode.query.limit !== -1) {
248
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, (_a = nestedNode.query.limit) !== null && _a !== void 0 ? _a : 100);
249
+ }
248
250
  parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
249
251
  // This is pre-filled in get-ast-from-query
250
252
  const sortField = nestedNode.query.sort[0];
@@ -46,19 +46,19 @@ fields:
46
46
  width: half
47
47
 
48
48
  - field: comment
49
- display: formatted-text
49
+ display: formatted-value
50
50
  display_options:
51
- subdued: true
51
+ color: 'var(--foreground-subdued)'
52
52
  width: half
53
53
 
54
54
  - field: user_agent
55
- display: formatted-text
55
+ display: formatted-value
56
56
  display_options:
57
57
  font: monospace
58
58
  width: half
59
59
 
60
60
  - field: ip
61
- display: formatted-text
61
+ display: formatted-value
62
62
  display_options:
63
63
  font: monospace
64
64
  width: half
@@ -84,3 +84,12 @@ fields:
84
84
  field: conditions
85
85
  hidden: true
86
86
  special: cast-json
87
+
88
+ - collection: directus_fields
89
+ field: validation
90
+ hidden: true
91
+ special: cast-json
92
+
93
+ - collection: directus_fields
94
+ field: validation_message
95
+ hidden: true
@@ -15,9 +15,17 @@ fields:
15
15
 
16
16
  - field: role
17
17
  width: half
18
+ special: m2o
19
+ display: related-values
20
+ display_options:
21
+ template: '{{ name }}'
18
22
 
19
23
  - field: user
20
24
  width: half
25
+ special: m2o
26
+ display: related-values
27
+ display_options:
28
+ template: '{{ email }}'
21
29
 
22
30
  - field: id
23
31
  width: half
@@ -25,6 +33,12 @@ fields:
25
33
  - field: bookmark
26
34
  width: half
27
35
 
36
+ - field: icon
37
+ width: half
38
+
39
+ - field: color
40
+ width: half
41
+
28
42
  - field: search
29
43
  width: half
30
44
 
@@ -32,7 +32,18 @@ fields:
32
32
  translations:
33
33
  language: en-US
34
34
  translations: Website
35
- width: full
35
+ width: half
36
+
37
+ - field: default_language
38
+ interface: system-language
39
+ options:
40
+ iconRight: language
41
+ placeholder: en-US
42
+ includeProjectDefault: false
43
+ translations:
44
+ language: en-US
45
+ translations: Default Language
46
+ width: half
36
47
 
37
48
  - field: branding_divider
38
49
  interface: presentation-divider
@@ -380,4 +391,5 @@ fields:
380
391
  placeholder: $t:fields.directus_settings.attribution_placeholder
381
392
 
382
393
  - field: translation_strings
394
+ special: cast-json
383
395
  hidden: true
package/dist/logger.js CHANGED
@@ -28,6 +28,7 @@ const pino_http_1 = __importStar(require("pino-http"));
28
28
  const get_config_from_env_1 = require("./utils/get-config-from-env");
29
29
  const url_1 = require("url");
30
30
  const env_1 = __importDefault(require("./env"));
31
+ const utils_1 = require("@directus/shared/utils");
31
32
  const pinoOptions = {
32
33
  level: env_1.default.LOG_LEVEL || 'info',
33
34
  redact: {
@@ -43,7 +44,7 @@ const loggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_', '
43
44
  // Expose custom log levels into formatter function
44
45
  if (loggerEnvConfig.levels) {
45
46
  const customLogLevels = {};
46
- for (const el of loggerEnvConfig.levels.split(',')) {
47
+ for (const el of (0, utils_1.toArray)(loggerEnvConfig.levels)) {
47
48
  const key_val = el.split(':');
48
49
  customLogLevels[key_val[0].trim()] = key_val[1].trim();
49
50
  }
@@ -16,6 +16,7 @@ const user_name_1 = require("../utils/user-name");
16
16
  const lodash_1 = require("lodash");
17
17
  const env_1 = __importDefault(require("../env"));
18
18
  const uuid_validate_1 = __importDefault(require("uuid-validate"));
19
+ const url_1 = require("../utils/url");
19
20
  class ActivityService extends items_1.ItemsService {
20
21
  constructor(options) {
21
22
  super('directus_activity', options);
@@ -70,7 +71,9 @@ ${(0, user_name_1.userName)(sender)} has mentioned you in a comment:
70
71
 
71
72
  ${comment}
72
73
 
73
- <a href="${env_1.default.PUBLIC_URL}/admin/content/${data.collection}/${data.item}">Click here to view.</a>
74
+ <a href="${new url_1.Url(env_1.default.PUBLIC_URL)
75
+ .addPath('admin', 'content', data.collection, data.item)
76
+ .toString()}">Click here to view.</a>
74
77
  `;
75
78
  await this.notificationsService.createOne({
76
79
  recipient: userID,
@@ -1,6 +1,6 @@
1
+ import { Accountability, PermissionsAction, SchemaOverview } from '@directus/shared/types';
1
2
  import { Knex } from 'knex';
2
3
  import { AbstractServiceOptions, AST, Item, PrimaryKey } from '../types';
3
- import { PermissionsAction, Accountability, SchemaOverview } from '@directus/shared/types';
4
4
  import { PayloadService } from './payload';
5
5
  export declare class AuthorizationService {
6
6
  knex: Knex;
@@ -4,14 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AuthorizationService = void 0;
7
+ const exceptions_1 = require("@directus/shared/exceptions");
8
+ const utils_1 = require("@directus/shared/utils");
7
9
  const lodash_1 = require("lodash");
8
10
  const database_1 = __importDefault(require("../database"));
9
- const exceptions_1 = require("../exceptions");
10
- const exceptions_2 = require("@directus/shared/exceptions");
11
- const utils_1 = require("@directus/shared/utils");
11
+ const exceptions_2 = require("../exceptions");
12
+ const strip_function_1 = require("../utils/strip-function");
12
13
  const items_1 = require("./items");
13
14
  const payload_1 = require("./payload");
14
- const strip_function_1 = require("../utils/strip-function");
15
15
  class AuthorizationService {
16
16
  constructor(options) {
17
17
  this.knex = options.knex || (0, database_1.default)();
@@ -32,7 +32,7 @@ class AuthorizationService {
32
32
  // If the permissions don't match the collections, you don't have permission to read all of them
33
33
  const uniqueCollectionsRequestedCount = (0, lodash_1.uniq)(collectionsRequested.map(({ collection }) => collection)).length;
34
34
  if (uniqueCollectionsRequestedCount !== permissionsForCollections.length) {
35
- throw new exceptions_1.ForbiddenException();
35
+ throw new exceptions_2.ForbiddenException();
36
36
  }
37
37
  validateFields(ast);
38
38
  validateFilterPermissions(ast, this.schema, this.accountability);
@@ -88,7 +88,7 @@ class AuthorizationService {
88
88
  continue;
89
89
  for (const column of Object.values(aliasMap)) {
90
90
  if (allowedFields.includes(column) === false)
91
- throw new exceptions_1.ForbiddenException();
91
+ throw new exceptions_2.ForbiddenException();
92
92
  }
93
93
  }
94
94
  }
@@ -101,65 +101,137 @@ class AuthorizationService {
101
101
  continue;
102
102
  const fieldKey = (0, strip_function_1.stripFunction)(childNode.name);
103
103
  if (allowedFields.includes(fieldKey) === false) {
104
- throw new exceptions_1.ForbiddenException();
104
+ throw new exceptions_2.ForbiddenException();
105
105
  }
106
106
  }
107
107
  }
108
108
  }
109
109
  function validateFilterPermissions(ast, schema, accountability) {
110
110
  var _a, _b, _c, _d, _e;
111
+ let requiredFieldPermissions = {};
111
112
  if (ast.type !== 'field') {
112
113
  if (ast.type === 'a2o') {
113
114
  for (const collection of Object.keys(ast.children)) {
114
- checkFilter(collection, (_c = (_b = (_a = ast.query) === null || _a === void 0 ? void 0 : _a[collection]) === null || _b === void 0 ? void 0 : _b.filter) !== null && _c !== void 0 ? _c : {});
115
+ requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, extractRequiredFieldPermissions(collection, (_c = (_b = (_a = ast.query) === null || _a === void 0 ? void 0 : _a[collection]) === null || _b === void 0 ? void 0 : _b.filter) !== null && _c !== void 0 ? _c : {}));
115
116
  for (const child of ast.children[collection]) {
116
- validateFilterPermissions(child, schema, accountability);
117
+ // Always add relational field as a deep child may have a filter
118
+ if (child.type !== 'field') {
119
+ (requiredFieldPermissions[collection] || (requiredFieldPermissions[collection] = new Set())).add(child.fieldKey);
120
+ }
121
+ requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, validateFilterPermissions(child, schema, accountability));
117
122
  }
118
123
  }
119
124
  }
120
125
  else {
121
- checkFilter(ast.name, (_e = (_d = ast.query) === null || _d === void 0 ? void 0 : _d.filter) !== null && _e !== void 0 ? _e : {});
126
+ requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, extractRequiredFieldPermissions(ast.name, (_e = (_d = ast.query) === null || _d === void 0 ? void 0 : _d.filter) !== null && _e !== void 0 ? _e : {}));
122
127
  for (const child of ast.children) {
123
- validateFilterPermissions(child, schema, accountability);
128
+ // Always add relational field as a deep child may have a filter
129
+ if (child.type !== 'field') {
130
+ (requiredFieldPermissions[ast.name] || (requiredFieldPermissions[ast.name] = new Set())).add(child.fieldKey);
131
+ }
132
+ requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, validateFilterPermissions(child, schema, accountability));
124
133
  }
125
134
  }
126
135
  }
127
- function checkFilter(collection, filter) {
128
- var _a;
129
- const permissions = (_a = accountability === null || accountability === void 0 ? void 0 : accountability.permissions) === null || _a === void 0 ? void 0 : _a.find((permission) => permission.collection === collection);
130
- if (!permissions)
131
- throw new exceptions_1.ForbiddenException();
132
- const allowedFields = permissions.fields || [];
133
- for (const [key, value] of Object.entries(filter)) {
134
- if (key.startsWith('_')) {
135
- // Continue checking for _and and _or
136
- if ((0, lodash_1.isArray)(value)) {
137
- for (const val of value) {
138
- checkFilter(collection, val);
136
+ if (ast.type === 'root') {
137
+ // Validate all required permissions once at the root level
138
+ checkFieldPermissions(requiredFieldPermissions);
139
+ }
140
+ return requiredFieldPermissions;
141
+ function extractRequiredFieldPermissions(collection, filter, parentCollection, parentField) {
142
+ return (0, lodash_1.reduce)(filter, function (result, filterValue, filterKey) {
143
+ if (filterKey.startsWith('_')) {
144
+ if (filterKey === '_and' || filterKey === '_or') {
145
+ if ((0, lodash_1.isArray)(filterValue)) {
146
+ for (const filter of filterValue) {
147
+ const requiredPermissions = extractRequiredFieldPermissions(collection, filter, parentCollection, parentField);
148
+ result = mergeRequiredFieldPermissions(result, requiredPermissions);
149
+ }
139
150
  }
151
+ return result;
140
152
  }
153
+ // Filter value is not a filter, so we should skip it
154
+ return result;
141
155
  }
142
156
  else {
143
- if (allowedFields.length !== 0 &&
144
- allowedFields.includes('*') === false &&
145
- allowedFields.includes(key) === false) {
146
- throw new exceptions_1.ForbiddenException();
157
+ if (collection) {
158
+ (result[collection] || (result[collection] = new Set())).add(filterKey);
147
159
  }
148
- const relation = schema.relations.find((relation) => {
149
- var _a;
150
- return ((relation.collection === collection && relation.field === key) ||
151
- (relation.related_collection === collection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field) === key));
152
- });
153
- // Field is a relation
154
- if (relation) {
155
- if (relation.related_collection === collection) {
156
- checkFilter(relation.collection, value);
160
+ else {
161
+ const relation = schema.relations.find((relation) => {
162
+ var _a;
163
+ return ((relation.collection === parentCollection && relation.field === parentField) ||
164
+ (relation.related_collection === parentCollection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field) === parentField));
165
+ });
166
+ if (relation) {
167
+ if (relation.related_collection === parentCollection) {
168
+ (result[relation.collection] || (result[relation.collection] = new Set())).add(filterKey);
169
+ parentCollection = relation.collection;
170
+ }
171
+ else {
172
+ (result[relation.related_collection] || (result[relation.related_collection] = new Set())).add(filterKey);
173
+ parentCollection = relation.related_collection;
174
+ }
157
175
  }
158
176
  else {
159
- checkFilter(relation.related_collection, value);
177
+ // Filter key not found in parent collection
178
+ throw new exceptions_2.ForbiddenException();
179
+ }
180
+ }
181
+ if (typeof filterValue === 'object') {
182
+ // Parent collection is undefined when we process the top level filter
183
+ if (!parentCollection)
184
+ parentCollection = collection;
185
+ for (const [childFilterKey, childFilterValue] of Object.entries(filterValue)) {
186
+ if (childFilterKey.startsWith('_')) {
187
+ if (childFilterKey === '_and' || childFilterKey === '_or') {
188
+ if ((0, lodash_1.isArray)(childFilterValue)) {
189
+ for (const filter of childFilterValue) {
190
+ const requiredPermissions = extractRequiredFieldPermissions('', filter, parentCollection, filterKey);
191
+ result = mergeRequiredFieldPermissions(result, requiredPermissions);
192
+ }
193
+ }
194
+ }
195
+ }
196
+ else {
197
+ const requiredPermissions = extractRequiredFieldPermissions('', filterValue, parentCollection, filterKey);
198
+ result = mergeRequiredFieldPermissions(result, requiredPermissions);
199
+ }
160
200
  }
161
201
  }
162
202
  }
203
+ return result;
204
+ }, {});
205
+ }
206
+ function mergeRequiredFieldPermissions(current, child) {
207
+ for (const collection of Object.keys(child)) {
208
+ if (!current[collection]) {
209
+ current[collection] = child[collection];
210
+ }
211
+ else {
212
+ current[collection] = new Set([...current[collection], ...child[collection]]);
213
+ }
214
+ }
215
+ return current;
216
+ }
217
+ function checkFieldPermissions(requiredPermissions) {
218
+ var _a;
219
+ if ((accountability === null || accountability === void 0 ? void 0 : accountability.admin) === true)
220
+ return;
221
+ for (const collection of Object.keys(requiredPermissions)) {
222
+ const permission = (_a = accountability === null || accountability === void 0 ? void 0 : accountability.permissions) === null || _a === void 0 ? void 0 : _a.find((permission) => permission.collection === collection && permission.action === 'read');
223
+ if (!permission || !permission.fields)
224
+ throw new exceptions_2.ForbiddenException();
225
+ const allowedFields = permission.fields;
226
+ if (allowedFields.includes('*'))
227
+ continue;
228
+ // Allow legacy permissions with an empty fields array, where id can be accessed
229
+ if (allowedFields.length === 0)
230
+ allowedFields.push('id');
231
+ for (const field of requiredPermissions[collection]) {
232
+ if (!allowedFields.includes(field))
233
+ throw new exceptions_2.ForbiddenException();
234
+ }
163
235
  }
164
236
  }
165
237
  }
@@ -222,20 +294,24 @@ class AuthorizationService {
222
294
  return permission.collection === collection && permission.action === action;
223
295
  });
224
296
  if (!permission)
225
- throw new exceptions_1.ForbiddenException();
297
+ throw new exceptions_2.ForbiddenException();
226
298
  // Check if you have permission to access the fields you're trying to access
227
299
  const allowedFields = permission.fields || [];
228
300
  if (allowedFields.includes('*') === false) {
229
301
  const keysInData = Object.keys(payload);
230
302
  const invalidKeys = keysInData.filter((fieldKey) => allowedFields.includes(fieldKey) === false);
231
303
  if (invalidKeys.length > 0) {
232
- throw new exceptions_1.ForbiddenException();
304
+ throw new exceptions_2.ForbiddenException();
233
305
  }
234
306
  }
235
307
  }
236
308
  const preset = (_e = permission.presets) !== null && _e !== void 0 ? _e : {};
237
309
  const payloadWithPresets = (0, lodash_1.merge)({}, preset, payload);
310
+ const fieldValidationRules = Object.values(this.schema.collections[collection].fields)
311
+ .map((field) => field.validation)
312
+ .filter((v) => v);
238
313
  const hasValidationRules = (0, lodash_1.isNil)(permission.validation) === false && Object.keys((_f = permission.validation) !== null && _f !== void 0 ? _f : {}).length > 0;
314
+ const hasFieldValidationRules = fieldValidationRules && fieldValidationRules.length > 0;
239
315
  const requiredColumns = [];
240
316
  for (const field of Object.values(this.schema.collections[collection].fields)) {
241
317
  const specials = (_g = field === null || field === void 0 ? void 0 : field.special) !== null && _g !== void 0 ? _g : [];
@@ -245,7 +321,7 @@ class AuthorizationService {
245
321
  requiredColumns.push(field);
246
322
  }
247
323
  }
248
- if (hasValidationRules === false && requiredColumns.length === 0) {
324
+ if (hasValidationRules === false && hasFieldValidationRules === false && requiredColumns.length === 0) {
249
325
  return payloadWithPresets;
250
326
  }
251
327
  if (requiredColumns.length > 0) {
@@ -265,8 +341,16 @@ class AuthorizationService {
265
341
  });
266
342
  }
267
343
  }
344
+ if (hasFieldValidationRules) {
345
+ if (permission.validation) {
346
+ permission.validation = { _and: [permission.validation, ...fieldValidationRules] };
347
+ }
348
+ else {
349
+ permission.validation = { _and: fieldValidationRules };
350
+ }
351
+ }
268
352
  const validationErrors = [];
269
- validationErrors.push(...(0, lodash_1.flatten)((0, utils_1.validatePayload)(permission.validation, payloadWithPresets).map((error) => error.details.map((details) => new exceptions_2.FailedValidationException(details)))));
353
+ validationErrors.push(...(0, lodash_1.flatten)((0, utils_1.validatePayload)(permission.validation, payloadWithPresets).map((error) => error.details.map((details) => new exceptions_1.FailedValidationException(details)))));
270
354
  if (validationErrors.length > 0)
271
355
  throw validationErrors;
272
356
  return payloadWithPresets;
@@ -286,14 +370,14 @@ class AuthorizationService {
286
370
  if (Array.isArray(pk)) {
287
371
  const result = await itemsService.readMany(pk, { ...query, limit: pk.length }, { permissionsAction: action });
288
372
  if (!result)
289
- throw new exceptions_1.ForbiddenException();
373
+ throw new exceptions_2.ForbiddenException();
290
374
  if (result.length !== pk.length)
291
- throw new exceptions_1.ForbiddenException();
375
+ throw new exceptions_2.ForbiddenException();
292
376
  }
293
377
  else {
294
378
  const result = await itemsService.readOne(pk, query, { permissionsAction: action });
295
379
  if (!result)
296
- throw new exceptions_1.ForbiddenException();
380
+ throw new exceptions_2.ForbiddenException();
297
381
  }
298
382
  }
299
383
  }