directus 9.1.2 → 9.3.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 (101) hide show
  1. package/dist/auth/drivers/ldap.js +11 -2
  2. package/dist/auth/drivers/oauth2.d.ts +1 -1
  3. package/dist/auth/drivers/oauth2.js +46 -19
  4. package/dist/auth/drivers/openid.d.ts +1 -1
  5. package/dist/auth/drivers/openid.js +34 -17
  6. package/dist/auth.js +5 -3
  7. package/dist/cli/commands/bootstrap/index.js +3 -2
  8. package/dist/cli/commands/database/install.js +2 -4
  9. package/dist/cli/commands/init/index.js +3 -7
  10. package/dist/cli/commands/schema/apply.js +26 -10
  11. package/dist/cli/utils/defaults.d.ts +11 -0
  12. package/dist/cli/utils/defaults.js +14 -0
  13. package/dist/controllers/assets.js +0 -27
  14. package/dist/controllers/auth.js +7 -2
  15. package/dist/controllers/extensions.js +1 -1
  16. package/dist/database/{functions/types.d.ts → helpers/date/dialects/mssql.d.ts} +2 -1
  17. package/dist/database/{functions → helpers/date}/dialects/mssql.js +4 -6
  18. package/dist/database/{functions → helpers/date}/dialects/mysql.d.ts +2 -4
  19. package/dist/database/{functions → helpers/date}/dialects/mysql.js +4 -6
  20. package/dist/database/{functions/dialects/mssql.d.ts → helpers/date/dialects/oracle.d.ts} +2 -4
  21. package/dist/database/{functions → helpers/date}/dialects/oracle.js +4 -6
  22. package/dist/database/helpers/date/dialects/postgres.d.ts +12 -0
  23. package/dist/database/{functions → helpers/date}/dialects/postgres.js +4 -6
  24. package/dist/database/{functions → helpers/date}/dialects/sqlite.d.ts +3 -4
  25. package/dist/database/helpers/date/dialects/sqlite.js +35 -0
  26. package/dist/database/helpers/date/index.d.ts +6 -0
  27. package/dist/database/helpers/date/index.js +15 -0
  28. package/dist/database/helpers/date/types.d.ts +13 -0
  29. package/dist/database/helpers/date/types.js +10 -0
  30. package/dist/database/helpers/geometry/dialects/mssql.d.ts +14 -0
  31. package/dist/database/helpers/geometry/dialects/mssql.js +36 -0
  32. package/dist/database/helpers/geometry/dialects/mysql.d.ts +7 -0
  33. package/dist/database/helpers/geometry/dialects/mysql.js +16 -0
  34. package/dist/database/helpers/geometry/dialects/oracle.d.ts +15 -0
  35. package/dist/database/helpers/geometry/dialects/oracle.js +39 -0
  36. package/dist/database/helpers/geometry/dialects/postgres.d.ts +10 -0
  37. package/dist/database/helpers/geometry/dialects/postgres.js +23 -0
  38. package/dist/database/helpers/geometry/dialects/redshift.d.ts +7 -0
  39. package/dist/database/helpers/geometry/dialects/redshift.js +16 -0
  40. package/dist/database/helpers/geometry/dialects/sqlite.d.ts +6 -0
  41. package/dist/database/helpers/geometry/dialects/sqlite.js +14 -0
  42. package/dist/database/helpers/geometry/index.d.ts +6 -0
  43. package/dist/database/helpers/geometry/index.js +15 -0
  44. package/dist/database/helpers/{geometry.d.ts → geometry/types.d.ts} +3 -7
  45. package/dist/database/helpers/geometry/types.js +54 -0
  46. package/dist/database/helpers/index.d.ts +8 -0
  47. package/dist/database/helpers/index.js +33 -0
  48. package/dist/database/helpers/types.d.ts +5 -0
  49. package/dist/database/helpers/types.js +9 -0
  50. package/dist/database/index.js +6 -6
  51. package/dist/database/run-ast.js +5 -5
  52. package/dist/database/seeds/run.js +3 -3
  53. package/dist/database/system-data/fields/notifications.yaml +1 -0
  54. package/dist/emitter.d.ts +3 -2
  55. package/dist/emitter.js +13 -6
  56. package/dist/env.js +1 -0
  57. package/dist/exceptions/index.d.ts +2 -0
  58. package/dist/exceptions/index.js +2 -0
  59. package/dist/exceptions/invalid-token.d.ts +4 -0
  60. package/dist/exceptions/invalid-token.js +10 -0
  61. package/dist/exceptions/unexpected-response.d.ts +4 -0
  62. package/dist/exceptions/unexpected-response.js +10 -0
  63. package/dist/extensions.d.ts +1 -0
  64. package/dist/extensions.js +22 -3
  65. package/dist/middleware/sanitize-query.js +1 -1
  66. package/dist/services/activity.js +7 -2
  67. package/dist/services/assets.js +14 -0
  68. package/dist/services/fields.d.ts +2 -0
  69. package/dist/services/fields.js +57 -26
  70. package/dist/services/files.d.ts +1 -1
  71. package/dist/services/files.js +27 -19
  72. package/dist/services/graphql.js +3 -0
  73. package/dist/services/items.js +18 -29
  74. package/dist/services/payload.d.ts +2 -0
  75. package/dist/services/payload.js +3 -3
  76. package/dist/services/users.js +8 -6
  77. package/dist/tests/database/migrations/run.test.d.ts +1 -0
  78. package/dist/tests/database/migrations/run.test.js +29 -0
  79. package/dist/types/extensions.d.ts +2 -0
  80. package/dist/utils/apply-query.js +9 -12
  81. package/dist/utils/apply-snapshot.js +91 -37
  82. package/dist/utils/get-column.js +2 -2
  83. package/dist/utils/get-default-index-name.js +2 -2
  84. package/dist/utils/get-local-type.js +1 -12
  85. package/dist/utils/get-permissions.d.ts +2 -2
  86. package/dist/utils/get-permissions.js +103 -66
  87. package/dist/utils/sanitize-query.js +1 -12
  88. package/dist/utils/validate-query.js +1 -1
  89. package/dist/webhooks.js +16 -24
  90. package/package.json +15 -14
  91. package/dist/database/functions/dialects/oracle.d.ts +0 -14
  92. package/dist/database/functions/dialects/postgres.d.ts +0 -14
  93. package/dist/database/functions/dialects/sqlite.js +0 -33
  94. package/dist/database/functions/index.d.ts +0 -3
  95. package/dist/database/functions/index.js +0 -26
  96. package/dist/database/functions/types.js +0 -2
  97. package/dist/database/helpers/date.d.ts +0 -8
  98. package/dist/database/helpers/date.js +0 -44
  99. package/dist/database/helpers/geometry.js +0 -189
  100. package/dist/utils/get-simple-hash.d.ts +0 -5
  101. package/dist/utils/get-simple-hash.js +0 -15
@@ -213,8 +213,16 @@ class ItemsService {
213
213
  if (records === null) {
214
214
  throw new exceptions_1.ForbiddenException();
215
215
  }
216
+ const filteredRecords = await emitter_1.default.emitFilter(`${this.eventScope}.read`, records, {
217
+ query,
218
+ collection: this.collection,
219
+ }, {
220
+ database: this.knex,
221
+ schema: this.schema,
222
+ accountability: this.accountability,
223
+ });
216
224
  emitter_1.default.emitAction(`${this.eventScope}.read`, {
217
- payload: records,
225
+ payload: filteredRecords,
218
226
  query,
219
227
  collection: this.collection,
220
228
  }, {
@@ -222,23 +230,15 @@ class ItemsService {
222
230
  schema: this.schema,
223
231
  accountability: this.accountability,
224
232
  });
225
- return records;
233
+ return filteredRecords;
226
234
  }
227
235
  /**
228
236
  * Get single item by primary key
229
237
  */
230
- async readOne(key, query, opts) {
231
- query = query !== null && query !== void 0 ? query : {};
238
+ async readOne(key, query = {}, opts) {
232
239
  const primaryKeyField = this.schema.collections[this.collection].primary;
233
- const queryWithKey = {
234
- ...query,
235
- filter: {
236
- ...(query.filter || {}),
237
- [primaryKeyField]: {
238
- _eq: key,
239
- },
240
- },
241
- };
240
+ const filterWithKey = (0, lodash_1.assign)({}, query.filter, { [primaryKeyField]: { _eq: key } });
241
+ const queryWithKey = (0, lodash_1.assign)({}, query, { filter: filterWithKey });
242
242
  const results = await this.readByQuery(queryWithKey, opts);
243
243
  if (results.length === 0) {
244
244
  throw new exceptions_1.ForbiddenException();
@@ -248,23 +248,12 @@ class ItemsService {
248
248
  /**
249
249
  * Get multiple items by primary keys
250
250
  */
251
- async readMany(keys, query, opts) {
252
- query = query !== null && query !== void 0 ? query : {};
251
+ async readMany(keys, query = {}, opts) {
252
+ var _a;
253
253
  const primaryKeyField = this.schema.collections[this.collection].primary;
254
- const queryWithKeys = {
255
- ...query,
256
- filter: {
257
- _and: [
258
- query.filter || {},
259
- {
260
- [primaryKeyField]: {
261
- _in: keys,
262
- },
263
- },
264
- ],
265
- },
266
- };
267
- const results = await this.readByQuery(queryWithKeys, opts);
254
+ const filterWithKey = { _and: [{ [primaryKeyField]: { _in: keys } }, (_a = query.filter) !== null && _a !== void 0 ? _a : {}] };
255
+ const queryWithKey = (0, lodash_1.assign)({}, query, { filter: filterWithKey });
256
+ const results = await this.readByQuery(queryWithKey, opts);
268
257
  return results;
269
258
  }
270
259
  /**
@@ -1,6 +1,7 @@
1
1
  import { Knex } from 'knex';
2
2
  import { AbstractServiceOptions, Item, PrimaryKey, SchemaOverview } from '../types';
3
3
  import { Accountability } from '@directus/shared/types';
4
+ import { Helpers } from '../database/helpers';
4
5
  declare type Action = 'create' | 'read' | 'update';
5
6
  declare type Transformers = {
6
7
  [type: string]: (context: {
@@ -18,6 +19,7 @@ declare type Transformers = {
18
19
  export declare class PayloadService {
19
20
  accountability: Accountability | null;
20
21
  knex: Knex;
22
+ helpers: Helpers;
21
23
  collection: string;
22
24
  schema: SchemaOverview;
23
25
  constructor(collection: string, options: AbstractServiceOptions);
@@ -13,7 +13,7 @@ const exceptions_1 = require("../exceptions");
13
13
  const utils_1 = require("@directus/shared/utils");
14
14
  const items_1 = require("./items");
15
15
  const flat_1 = require("flat");
16
- const geometry_1 = require("../database/helpers/geometry");
16
+ const helpers_1 = require("../database/helpers");
17
17
  const wellknown_1 = require("wellknown");
18
18
  const generate_hash_1 = require("../utils/generate-hash");
19
19
  /**
@@ -111,6 +111,7 @@ class PayloadService {
111
111
  };
112
112
  this.accountability = options.accountability || null;
113
113
  this.knex = options.knex || (0, database_1.default)();
114
+ this.helpers = (0, helpers_1.getHelpers)(this.knex);
114
115
  this.collection = collection;
115
116
  this.schema = options.schema;
116
117
  return this;
@@ -188,10 +189,9 @@ class PayloadService {
188
189
  * to check if the value is a raw instance before stringifying it in the next step.
189
190
  */
190
191
  processGeometries(payloads, action) {
191
- const helper = (0, geometry_1.getGeometryHelper)();
192
192
  const process = action == 'read'
193
193
  ? (value) => (typeof value === 'string' ? (0, wellknown_1.parse)(value) : value)
194
- : (value) => helper.fromGeoJSON(typeof value == 'string' ? JSON.parse(value) : value);
194
+ : (value) => this.helpers.st.fromGeoJSON(typeof value == 'string' ? JSON.parse(value) : value);
195
195
  const fieldsInCollection = Object.entries(this.schema.collections[this.collection].fields);
196
196
  const geometryColumns = fieldsInCollection.filter(([_, field]) => field.type.startsWith('geometry'));
197
197
  for (const [name] of geometryColumns) {
@@ -19,6 +19,7 @@ const mail_1 = require("./mail");
19
19
  const settings_1 = require("./settings");
20
20
  const stall_1 = require("../utils/stall");
21
21
  const perf_hooks_1 = require("perf_hooks");
22
+ const utils_2 = require("@directus/shared/utils");
22
23
  class UsersService extends items_1.ItemsService {
23
24
  constructor(options) {
24
25
  super('directus_users', options);
@@ -251,7 +252,7 @@ class UsersService extends items_1.ItemsService {
251
252
  }
252
253
  const STALL_TIME = 500;
253
254
  const timeStart = perf_hooks_1.performance.now();
254
- const user = await this.knex.select('status').from('directus_users').where({ email }).first();
255
+ const user = await this.knex.select('status', 'password').from('directus_users').where({ email }).first();
255
256
  if ((user === null || user === void 0 ? void 0 : user.status) !== 'active') {
256
257
  await (0, stall_1.stall)(STALL_TIME, timeStart);
257
258
  throw new exceptions_2.ForbiddenException();
@@ -261,7 +262,7 @@ class UsersService extends items_1.ItemsService {
261
262
  knex: this.knex,
262
263
  accountability: this.accountability,
263
264
  });
264
- const payload = { email, scope: 'password-reset' };
265
+ const payload = { email, scope: 'password-reset', hash: (0, utils_2.getSimpleHash)('' + user.password) };
265
266
  const token = jsonwebtoken_1.default.sign(payload, env_1.default.SECRET, { expiresIn: '1d', issuer: 'directus' });
266
267
  const acceptURL = url ? `${url}?token=${token}` : `${env_1.default.PUBLIC_URL}/admin/reset-password?token=${token}`;
267
268
  const subjectLine = subject ? subject : 'Password Reset Request';
@@ -279,11 +280,12 @@ class UsersService extends items_1.ItemsService {
279
280
  await (0, stall_1.stall)(STALL_TIME, timeStart);
280
281
  }
281
282
  async resetPassword(token, password) {
282
- const { email, scope } = jsonwebtoken_1.default.verify(token, env_1.default.SECRET, { issuer: 'directus' });
283
- if (scope !== 'password-reset')
283
+ const { email, scope, hash } = jsonwebtoken_1.default.verify(token, env_1.default.SECRET, { issuer: 'directus' });
284
+ if (scope !== 'password-reset' || !hash)
284
285
  throw new exceptions_2.ForbiddenException();
285
- const user = await this.knex.select('id', 'status').from('directus_users').where({ email }).first();
286
- if ((user === null || user === void 0 ? void 0 : user.status) !== 'active') {
286
+ await this.checkPasswordPolicy([password]);
287
+ const user = await this.knex.select('id', 'status', 'password').from('directus_users').where({ email }).first();
288
+ if ((user === null || user === void 0 ? void 0 : user.status) !== 'active' || hash !== (0, utils_2.getSimpleHash)('' + user.password)) {
287
289
  throw new exceptions_2.ForbiddenException();
288
290
  }
289
291
  // Allow unauthenticated update
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
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 knex_1 = __importDefault(require("knex"));
7
+ const knex_mock_client_1 = require("knex-mock-client");
8
+ const run_1 = __importDefault(require("../../../database/migrations/run"));
9
+ describe('run', () => {
10
+ let db;
11
+ let tracker;
12
+ beforeAll(() => {
13
+ db = (0, knex_1.default)({ client: knex_mock_client_1.MockClient });
14
+ tracker = (0, knex_mock_client_1.getTracker)();
15
+ });
16
+ afterEach(() => {
17
+ tracker.reset();
18
+ });
19
+ describe('when passed the argument up', () => {
20
+ it('returns "Nothing To Updage" if no directus_migrations', async () => {
21
+ // note the difference between an empty array and ['Empty']
22
+ tracker.on.select('directus_migrations').response(['Empty']);
23
+ await (0, run_1.default)(db, 'up').catch((e) => {
24
+ expect(e).toBeInstanceOf(Error);
25
+ expect(e.message).toBe('Nothing to upgrade');
26
+ });
27
+ });
28
+ });
29
+ });
@@ -5,6 +5,7 @@ import { Logger } from 'pino';
5
5
  import env from '../env';
6
6
  import * as exceptions from '../exceptions';
7
7
  import * as services from '../services';
8
+ import { Emitter } from '../emitter';
8
9
  import { getSchema } from '../utils/get-schema';
9
10
  import { SchemaOverview } from './schema';
10
11
  export declare type ExtensionContext = {
@@ -12,6 +13,7 @@ export declare type ExtensionContext = {
12
13
  exceptions: typeof exceptions;
13
14
  database: Knex;
14
15
  env: typeof env;
16
+ emitter: Emitter;
15
17
  logger: Logger;
16
18
  getSchema: typeof getSchema;
17
19
  };
@@ -8,11 +8,9 @@ const lodash_1 = require("lodash");
8
8
  const nanoid_1 = require("nanoid");
9
9
  const uuid_validate_1 = __importDefault(require("uuid-validate"));
10
10
  const exceptions_1 = require("../exceptions");
11
- const apply_function_to_column_name_1 = require("./apply-function-to-column-name");
12
11
  const get_column_1 = require("./get-column");
13
12
  const get_relation_type_1 = require("./get-relation-type");
14
- const geometry_1 = require("../database/helpers/geometry");
15
- const date_1 = require("../database/helpers/date");
13
+ const helpers_1 = require("../database/helpers");
16
14
  const generateAlias = (0, nanoid_1.customAlphabet)('abcdefghijklmnopqrstuvwxyz', 5);
17
15
  /**
18
16
  * Apply the Query to a given Knex query builder instance
@@ -45,7 +43,7 @@ function applyQuery(knex, collection, dbQuery, query, schema, subQuery = false)
45
43
  applySearch(schema, dbQuery, query.search, collection);
46
44
  }
47
45
  if (query.group) {
48
- dbQuery.groupBy(query.group.map(apply_function_to_column_name_1.applyFunctionToColumnName));
46
+ dbQuery.groupBy(query.group.map((column) => (0, get_column_1.getColumn)(knex, collection, column, false)));
49
47
  }
50
48
  if (query.aggregate) {
51
49
  applyAggregate(dbQuery, query.aggregate, collection);
@@ -117,6 +115,7 @@ exports.default = applyQuery;
117
115
  * ```
118
116
  */
119
117
  function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery = false) {
118
+ const helpers = (0, helpers_1.getHelpers)(knex);
120
119
  const relations = schema.relations;
121
120
  const aliasMap = {};
122
121
  addJoins(rootQuery, rootFilter, collection);
@@ -273,16 +272,15 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
273
272
  query.where(key, '!=', '');
274
273
  });
275
274
  }
276
- const dateHelper = (0, date_1.getDateHelper)();
277
275
  const [collection, field] = key.split('.');
278
276
  if (collection in schema.collections && field in schema.collections[collection].fields) {
279
277
  const type = schema.collections[collection].fields[field].type;
280
278
  if (['date', 'dateTime', 'time', 'timestamp'].includes(type)) {
281
279
  if (Array.isArray(compareValue)) {
282
- compareValue = compareValue.map((val) => dateHelper.parseDate(val));
280
+ compareValue = compareValue.map((val) => helpers.date.parse(val));
283
281
  }
284
282
  else {
285
- compareValue = dateHelper.parseDate(compareValue);
283
+ compareValue = helpers.date.parse(compareValue);
286
284
  }
287
285
  }
288
286
  }
@@ -361,18 +359,17 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
361
359
  value = value.split(',');
362
360
  dbQuery[logical].whereNotBetween(selectionRaw, value);
363
361
  }
364
- const geometryHelper = (0, geometry_1.getGeometryHelper)();
365
362
  if (operator == '_intersects') {
366
- dbQuery[logical].whereRaw(geometryHelper.intersects(key, compareValue));
363
+ dbQuery[logical].whereRaw(helpers.st.intersects(key, compareValue));
367
364
  }
368
365
  if (operator == '_nintersects') {
369
- dbQuery[logical].whereRaw(geometryHelper.nintersects(key, compareValue));
366
+ dbQuery[logical].whereRaw(helpers.st.nintersects(key, compareValue));
370
367
  }
371
368
  if (operator == '_intersects_bbox') {
372
- dbQuery[logical].whereRaw(geometryHelper.intersects_bbox(key, compareValue));
369
+ dbQuery[logical].whereRaw(helpers.st.intersects_bbox(key, compareValue));
373
370
  }
374
371
  if (operator == '_nintersects_bbox') {
375
- dbQuery[logical].whereRaw(geometryHelper.nintersects_bbox(key, compareValue));
372
+ dbQuery[logical].whereRaw(helpers.st.nintersects_bbox(key, compareValue));
376
373
  }
377
374
  }
378
375
  function getWhereColumn(path, collection) {
@@ -10,6 +10,7 @@ const database_1 = __importDefault(require("../database"));
10
10
  const get_schema_1 = require("./get-schema");
11
11
  const services_1 = require("../services");
12
12
  const lodash_1 = require("lodash");
13
+ const logger_1 = __importDefault(require("../logger"));
13
14
  async function applySnapshot(snapshot, options) {
14
15
  var _a, _b, _c, _d;
15
16
  const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
@@ -20,7 +21,13 @@ async function applySnapshot(snapshot, options) {
20
21
  const collectionsService = new services_1.CollectionsService({ knex: trx, schema });
21
22
  for (const { collection, diff } of snapshotDiff.collections) {
22
23
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
23
- await collectionsService.deleteOne(collection);
24
+ try {
25
+ await collectionsService.deleteOne(collection);
26
+ }
27
+ catch (err) {
28
+ logger_1.default.error(`Failed to delete collection "${collection}"`);
29
+ throw err;
30
+ }
24
31
  }
25
32
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N' && diff[0].rhs) {
26
33
  // We'll nest the to-be-created fields in the same collection creation, to prevent
@@ -28,65 +35,112 @@ async function applySnapshot(snapshot, options) {
28
35
  const fields = snapshotDiff.fields
29
36
  .filter((fieldDiff) => fieldDiff.collection === collection)
30
37
  .map((fieldDiff) => fieldDiff.diff[0].rhs);
31
- await collectionsService.createOne({
32
- ...diff[0].rhs,
33
- fields,
34
- });
38
+ try {
39
+ await collectionsService.createOne({
40
+ ...diff[0].rhs,
41
+ fields,
42
+ });
43
+ }
44
+ catch (err) {
45
+ logger_1.default.error(`Failed to create collection "${collection}"`);
46
+ throw err;
47
+ }
35
48
  // Now that the fields are in for this collection, we can strip them from the field
36
49
  // edits
37
50
  snapshotDiff.fields = snapshotDiff.fields.filter((fieldDiff) => fieldDiff.collection !== collection);
38
51
  }
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);
52
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
53
+ const newValues = snapshot.collections.find((field) => {
54
+ return field.collection === collection;
55
+ });
56
+ if (newValues) {
57
+ try {
58
+ await collectionsService.updateOne(collection, newValues);
59
+ }
60
+ catch (err) {
61
+ logger_1.default.error(`Failed to update collection "${collection}"`);
62
+ throw err;
63
+ }
64
+ }
47
65
  }
48
66
  }
49
67
  const fieldsService = new services_1.FieldsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
50
68
  for (const { collection, field, diff } of snapshotDiff.fields) {
51
69
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
52
- await fieldsService.createField(collection, diff[0].rhs);
70
+ try {
71
+ await fieldsService.createField(collection, diff[0].rhs);
72
+ }
73
+ catch (err) {
74
+ logger_1.default.error(`Failed to create field "${collection}.${field}"`);
75
+ throw err;
76
+ }
53
77
  }
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,
78
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
79
+ const newValues = snapshot.fields.find((snapshotField) => {
80
+ return snapshotField.collection === collection && snapshotField.field === field;
65
81
  });
82
+ if (newValues) {
83
+ try {
84
+ await fieldsService.updateField(collection, {
85
+ ...newValues,
86
+ });
87
+ }
88
+ catch (err) {
89
+ logger_1.default.error(`Failed to update field "${collection}.${field}"`);
90
+ throw err;
91
+ }
92
+ }
66
93
  }
67
94
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
68
- await fieldsService.deleteField(collection, field);
95
+ try {
96
+ await fieldsService.deleteField(collection, field);
97
+ }
98
+ catch (err) {
99
+ logger_1.default.error(`Failed to delete field "${collection}.${field}"`);
100
+ throw err;
101
+ }
69
102
  // Field deletion also cleans up the relationship. We should ignore any relationship
70
103
  // changes attached to this now non-existing field
71
104
  snapshotDiff.relations = snapshotDiff.relations.filter((relation) => (relation.collection === collection && relation.field === field) === false);
72
105
  }
73
106
  }
74
107
  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) {
108
+ for (const { collection, field, diff } of snapshotDiff.relations) {
109
+ const structure = {};
110
+ for (const diffEdit of diff) {
111
+ (0, lodash_1.set)(structure, diffEdit.path, undefined);
112
+ }
76
113
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
77
- await relationsService.createOne(diff[0].rhs);
114
+ try {
115
+ await relationsService.createOne(diff[0].rhs);
116
+ }
117
+ catch (err) {
118
+ logger_1.default.error(`Failed to create relation "${collection}.${field}"`);
119
+ throw err;
120
+ }
78
121
  }
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);
122
+ if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
123
+ const newValues = snapshot.relations.find((relation) => {
124
+ return relation.collection === collection && relation.field === field;
125
+ });
126
+ if (newValues) {
127
+ try {
128
+ await relationsService.updateOne(collection, field, newValues);
129
+ }
130
+ catch (err) {
131
+ logger_1.default.error(`Failed to update relation "${collection}.${field}"`);
132
+ throw err;
133
+ }
134
+ }
87
135
  }
88
136
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
89
- await relationsService.deleteOne(collection, field);
137
+ try {
138
+ await relationsService.deleteOne(collection, field);
139
+ }
140
+ catch (err) {
141
+ logger_1.default.error(`Failed to delete relation "${collection}.${field}"`);
142
+ throw err;
143
+ }
90
144
  }
91
145
  }
92
146
  });
@@ -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',
@@ -100,8 +95,6 @@ const localTypeMap = {
100
95
  integerfirst: 'integer',
101
96
  };
102
97
  function getLocalType(column, field) {
103
- const database = (0, database_2.default)();
104
- const databaseClient = (0, database_1.getDatabaseClient)(database);
105
98
  if (!column)
106
99
  return 'alias';
107
100
  const dataType = column.data_type.toLowerCase();
@@ -125,13 +118,9 @@ function getLocalType(column, field) {
125
118
  return 'decimal';
126
119
  }
127
120
  /** Handle MS SQL varchar(MAX) (eg TEXT) types */
128
- if (dataType === 'nvarchar(MAX)') {
121
+ if (column.data_type === 'nvarchar' && column.max_length === -1) {
129
122
  return 'text';
130
123
  }
131
- /** Handle Boolean as TINYINT and edgecase MySQL where it still is just tinyint */
132
- if (databaseClient === 'mysql' && dataType === 'tinyint(1)') {
133
- return 'boolean';
134
- }
135
124
  return type !== null && type !== void 0 ? type : 'unknown';
136
125
  }
137
126
  exports.default = getLocalType;
@@ -1,3 +1,3 @@
1
- import { Accountability } from '@directus/shared/types';
1
+ import { Permission, Accountability } from '@directus/shared/types';
2
2
  import { SchemaOverview } from '../types';
3
- export declare function getPermissions(accountability: Accountability, schema: SchemaOverview): Promise<any>;
3
+ export declare function getPermissions(accountability: Accountability, schema: SchemaOverview): Promise<Permission[]>;