directus 9.20.4 → 9.21.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 (135) hide show
  1. package/dist/cli/utils/create-db-connection.d.ts +1 -1
  2. package/dist/controllers/extensions.js +4 -13
  3. package/dist/database/helpers/date/dialects/sqlite.d.ts +1 -1
  4. package/dist/database/helpers/date/dialects/sqlite.js +4 -0
  5. package/dist/database/helpers/date/types.d.ts +1 -1
  6. package/dist/database/helpers/date/types.js +4 -0
  7. package/dist/database/helpers/fn/dialects/mssql.d.ts +8 -8
  8. package/dist/database/helpers/fn/dialects/mssql.js +22 -16
  9. package/dist/database/helpers/fn/dialects/mysql.d.ts +8 -8
  10. package/dist/database/helpers/fn/dialects/mysql.js +22 -16
  11. package/dist/database/helpers/fn/dialects/postgres.d.ts +8 -8
  12. package/dist/database/helpers/fn/dialects/postgres.js +22 -16
  13. package/dist/database/helpers/fn/types.d.ts +1 -1
  14. package/dist/database/helpers/index.d.ts +1 -1
  15. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +1 -0
  16. package/dist/database/helpers/schema/dialects/cockroachdb.js +11 -0
  17. package/dist/database/helpers/schema/types.d.ts +3 -2
  18. package/dist/database/helpers/schema/types.js +5 -0
  19. package/dist/database/migrations/run.js +29 -3
  20. package/dist/database/run-ast.d.ts +1 -1
  21. package/dist/database/run-ast.js +1 -1
  22. package/dist/env.d.ts +4 -0
  23. package/dist/env.js +9 -4
  24. package/dist/env.test.d.ts +1 -8
  25. package/dist/exceptions/database/contains-null-values.d.ts +1 -1
  26. package/dist/exceptions/database/dialects/types.d.ts +6 -6
  27. package/dist/exceptions/database/invalid-foreign-key.d.ts +1 -1
  28. package/dist/exceptions/database/not-null-violation.d.ts +1 -1
  29. package/dist/exceptions/database/record-not-unique.d.ts +1 -1
  30. package/dist/exceptions/database/value-out-of-range.d.ts +1 -1
  31. package/dist/exceptions/database/value-too-long.d.ts +1 -1
  32. package/dist/exceptions/hit-rate-limit.d.ts +1 -1
  33. package/dist/exceptions/method-not-allowed.d.ts +1 -1
  34. package/dist/exceptions/service-unavailable.d.ts +1 -1
  35. package/dist/extensions.d.ts +7 -7
  36. package/dist/extensions.js +92 -89
  37. package/dist/logger.d.ts +1 -0
  38. package/dist/messenger.d.ts +1 -1
  39. package/dist/middleware/authenticate.d.ts +1 -0
  40. package/dist/middleware/validate-batch.d.ts +2 -0
  41. package/dist/operations/condition/index.d.ts +1 -1
  42. package/dist/operations/condition/index.js +1 -1
  43. package/dist/operations/condition/index.test.d.ts +1 -0
  44. package/dist/operations/exec/index.d.ts +1 -1
  45. package/dist/operations/item-create/index.d.ts +1 -1
  46. package/dist/operations/item-delete/index.d.ts +1 -1
  47. package/dist/operations/item-read/index.d.ts +1 -1
  48. package/dist/operations/item-update/index.d.ts +1 -1
  49. package/dist/operations/log/index.d.ts +1 -1
  50. package/dist/operations/mail/index.d.ts +1 -1
  51. package/dist/operations/notification/index.d.ts +1 -1
  52. package/dist/operations/request/index.d.ts +1 -1
  53. package/dist/operations/sleep/index.d.ts +1 -1
  54. package/dist/operations/transform/index.d.ts +1 -1
  55. package/dist/operations/trigger/index.d.ts +1 -1
  56. package/dist/operations/trigger/index.js +5 -2
  57. package/dist/rate-limiter.d.ts +1 -1
  58. package/dist/services/authorization.js +7 -3
  59. package/dist/services/collections.d.ts +1 -1
  60. package/dist/services/collections.js +112 -13
  61. package/dist/services/fields.d.ts +2 -2
  62. package/dist/services/fields.js +89 -41
  63. package/dist/services/fields.test.d.ts +1 -0
  64. package/dist/services/graphql/index.js +4 -1
  65. package/dist/services/graphql/utils/process-error.d.ts +4 -0
  66. package/dist/services/graphql/utils/process-error.js +26 -0
  67. package/dist/services/graphql/utils/process-error.test.d.ts +1 -0
  68. package/dist/services/items.d.ts +1 -1
  69. package/dist/services/items.js +39 -13
  70. package/dist/services/mail/index.d.ts +2 -2
  71. package/dist/services/mail/index.js +2 -1
  72. package/dist/services/mail/templates/base.liquid +4 -4
  73. package/dist/services/notifications.js +9 -4
  74. package/dist/services/notifications.test.d.ts +1 -0
  75. package/dist/services/payload.d.ts +2 -2
  76. package/dist/services/payload.js +14 -12
  77. package/dist/services/relations.d.ts +2 -2
  78. package/dist/services/relations.js +54 -4
  79. package/dist/services/users.js +2 -2
  80. package/dist/services/users.test.d.ts +1 -0
  81. package/dist/types/assets.d.ts +7 -7
  82. package/dist/types/ast.d.ts +7 -7
  83. package/dist/types/auth.d.ts +4 -4
  84. package/dist/types/collection.d.ts +2 -2
  85. package/dist/types/events.d.ts +1 -1
  86. package/dist/types/files.d.ts +2 -2
  87. package/dist/types/items.d.ts +5 -5
  88. package/dist/types/migration.d.ts +1 -1
  89. package/dist/types/revision.d.ts +1 -1
  90. package/dist/types/services.d.ts +1 -1
  91. package/dist/types/snapshot.d.ts +4 -4
  92. package/dist/types/webhooks.d.ts +2 -2
  93. package/dist/utils/get-ast-from-query.d.ts +1 -1
  94. package/dist/utils/get-column-path.d.ts +2 -2
  95. package/dist/utils/get-module-default.d.ts +1 -1
  96. package/dist/utils/get-relation-info.d.ts +1 -1
  97. package/dist/utils/job-queue.d.ts +1 -1
  98. package/dist/utils/merge-permissions.d.ts +1 -0
  99. package/dist/utils/reduce-schema.js +3 -1
  100. package/package.json +70 -71
  101. package/dist/__mocks__/cache.d.ts +0 -5
  102. package/dist/__mocks__/cache.js +0 -7
  103. package/dist/__utils__/items-utils.d.ts +0 -2
  104. package/dist/__utils__/items-utils.js +0 -36
  105. package/dist/__utils__/schemas.d.ts +0 -13
  106. package/dist/__utils__/schemas.js +0 -304
  107. package/dist/__utils__/snapshots.d.ts +0 -5
  108. package/dist/__utils__/snapshots.js +0 -897
  109. package/dist/cli/index.test.js +0 -63
  110. package/dist/controllers/files.test.js +0 -49
  111. package/dist/database/migrations/run.test.js +0 -92
  112. package/dist/env.test.js +0 -40
  113. package/dist/middleware/authenticate.test.js +0 -214
  114. package/dist/middleware/extract-token.test.js +0 -60
  115. package/dist/middleware/validate-batch.test.js +0 -82
  116. package/dist/operations/exec/index.test.js +0 -95
  117. package/dist/services/files.test.js +0 -89
  118. package/dist/services/items.test.js +0 -765
  119. package/dist/services/payload.test.js +0 -196
  120. package/dist/services/specifications.test.js +0 -96
  121. package/dist/utils/apply-snapshot.test.js +0 -305
  122. package/dist/utils/async-handler.test.js +0 -18
  123. package/dist/utils/calculate-field-depth.test.js +0 -76
  124. package/dist/utils/filter-items.test.js +0 -60
  125. package/dist/utils/get-auth-providers.test.js +0 -72
  126. package/dist/utils/get-cache-key.test.js +0 -74
  127. package/dist/utils/get-column-path.test.js +0 -136
  128. package/dist/utils/get-config-from-env.test.js +0 -19
  129. package/dist/utils/get-relation-info.test.js +0 -88
  130. package/dist/utils/get-relation-type.test.js +0 -69
  131. package/dist/utils/get-string-byte-size.test.js +0 -8
  132. package/dist/utils/is-directus-jwt.test.js +0 -26
  133. package/dist/utils/jwt.test.js +0 -36
  134. package/dist/utils/merge-permissions.test.js +0 -80
  135. package/dist/utils/validate-keys.test.js +0 -97
@@ -1,765 +0,0 @@
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 services_1 = require("../../src/services");
9
- const items_utils_1 = require("../__utils__/items-utils");
10
- const schemas_1 = require("../__utils__/schemas");
11
- const lodash_1 = require("lodash");
12
- jest.mock('../../src/database/index', () => {
13
- return { getDatabaseClient: jest.fn().mockReturnValue('postgres') };
14
- });
15
- jest.requireMock('../../src/database/index');
16
- describe('Integration Tests', () => {
17
- let db;
18
- let tracker;
19
- const schemas = {
20
- system: { schema: schemas_1.systemSchema, tables: Object.keys(schemas_1.systemSchema.collections) },
21
- user: { schema: schemas_1.userSchema, tables: Object.keys(schemas_1.userSchema.collections) },
22
- };
23
- beforeAll(async () => {
24
- db = (0, knex_1.default)({ client: knex_mock_client_1.MockClient });
25
- tracker = (0, knex_mock_client_1.getTracker)();
26
- });
27
- afterEach(() => {
28
- tracker.reset();
29
- });
30
- describe('createOne', () => {
31
- const item = { id: '6107c897-9182-40f7-b22e-4f044d1258d2', name: 'A.G.' };
32
- it.each(Object.keys(schemas))(`%s creates one item in collection as an admin, accountability: "null"`, async (schema) => {
33
- const table = schemas[schema].tables[0];
34
- const itemsService = new services_1.ItemsService(table, {
35
- knex: db,
36
- accountability: { role: 'admin', admin: true },
37
- schema: schemas[schema].schema,
38
- });
39
- tracker.on.insert(table).responseOnce(item);
40
- const response = await itemsService.createOne(item, { emitEvents: false });
41
- expect(tracker.history.insert.length).toBe(1);
42
- expect(tracker.history.insert[0].bindings).toStrictEqual([item.id, item.name]);
43
- expect(tracker.history.insert[0].sql).toBe(`insert into "${table}" (${(0, items_utils_1.sqlFieldList)(schemas[schema].schema, table)}) values (?, ?)`);
44
- expect(response).toBe(item.id);
45
- });
46
- });
47
- describe('readOne', () => {
48
- const rawItems = [{ id: 'b5a7dd0f-fc9f-4242-b331-83990990198f' }, { id: '6107c897-9182-40f7-b22e-4f044d1258d2' }];
49
- describe('Permissions, Authorization, Roles', () => {
50
- it.each(Object.keys(schemas))('%s it returns one item from tables as admin', async (schema) => {
51
- const table = schemas[schema].tables[0];
52
- tracker.on.select(table).responseOnce(rawItems);
53
- // tracker.on.select(schemas[schema].tables[1]).responseOnce([]);
54
- const itemsService = new services_1.ItemsService(table, {
55
- knex: db,
56
- accountability: { role: 'admin', admin: true },
57
- schema: schemas[schema].schema,
58
- });
59
- const response = await itemsService.readOne(rawItems[0].id, { fields: ['id', 'name'] });
60
- expect(tracker.history.select.length).toBe(1);
61
- expect(tracker.history.select[0].bindings).toStrictEqual([rawItems[0].id, 100]);
62
- expect(tracker.history.select[0].sql).toBe(`select ${(0, items_utils_1.sqlFieldFormatter)(schemas[schema].schema, table)} from "${table}" where "${table}"."id" = ? order by "${table}"."id" asc limit ?`);
63
- expect(response).toStrictEqual(rawItems[0]);
64
- });
65
- it.each(Object.keys(schemas))('%s returns one item from tables not as admin but has permissions', async (schema) => {
66
- const table = schemas[schema].tables[0];
67
- tracker.on.select(table).responseOnce(rawItems);
68
- const itemsService = new services_1.ItemsService(table, {
69
- knex: db,
70
- accountability: {
71
- role: 'admin',
72
- admin: false,
73
- permissions: [
74
- {
75
- id: 1,
76
- role: 'admin',
77
- collection: table,
78
- action: 'read',
79
- permissions: {},
80
- validation: {},
81
- presets: {},
82
- fields: [],
83
- },
84
- ],
85
- },
86
- schema: schemas[schema].schema,
87
- });
88
- const response = await itemsService.readOne(rawItems[0].id);
89
- expect(tracker.history.select.length).toBe(1);
90
- expect(tracker.history.select[0].bindings).toStrictEqual([rawItems[0].id, 100]);
91
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id" from "${table}" where ("${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
92
- expect(response).toStrictEqual(rawItems[0].id);
93
- });
94
- it.each(Object.keys(schemas))('%s returns one item with filter from tables as admin', async (schema) => {
95
- const table = schemas[schema].tables[0];
96
- tracker.on.select(table).responseOnce(rawItems);
97
- const itemsService = new services_1.ItemsService(table, {
98
- knex: db,
99
- accountability: { role: 'admin', admin: true },
100
- schema: schemas[schema].schema,
101
- });
102
- const response = await itemsService.readOne(rawItems[0].id, {
103
- fields: ['id', 'name'],
104
- filter: { name: { _eq: 'something' } },
105
- });
106
- expect(tracker.history.select.length).toBe(1);
107
- expect(tracker.history.select[0].bindings).toStrictEqual(['something', rawItems[0].id, 100]);
108
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id", "${table}"."name" from "${table}" where "${table}"."name" = ? and "${table}"."id" = ? order by "${table}"."id" asc limit ?`);
109
- expect(response).toStrictEqual({ id: rawItems[0].id });
110
- });
111
- it.each(Object.keys(schemas))('%s returns one item with filter from tables not as admin but has field permissions', async (schema) => {
112
- const table = schemas[schema].tables[0];
113
- tracker.on.select(table).responseOnce(rawItems);
114
- const itemsService = new services_1.ItemsService(table, {
115
- knex: db,
116
- accountability: {
117
- role: 'admin',
118
- admin: false,
119
- permissions: [
120
- {
121
- id: 1,
122
- role: 'admin',
123
- collection: table,
124
- action: 'create',
125
- permissions: {},
126
- validation: {},
127
- presets: {},
128
- fields: ['*'],
129
- },
130
- {
131
- id: 2,
132
- role: 'admin',
133
- collection: table,
134
- action: 'read',
135
- permissions: {},
136
- validation: {},
137
- presets: {},
138
- fields: ['id', 'name'],
139
- },
140
- ],
141
- },
142
- schema: schemas[schema].schema,
143
- });
144
- const response = await itemsService.readOne(rawItems[0].id, {
145
- fields: ['id', 'name'],
146
- filter: { name: { _eq: 'something' } },
147
- });
148
- expect(tracker.history.select.length).toBe(1);
149
- expect(tracker.history.select[0].bindings).toStrictEqual(['something', rawItems[0].id, 100]);
150
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id", "${table}"."name" from "${table}" where ("${table}"."name" = ? and "${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
151
- expect(response).toStrictEqual({ id: rawItems[0].id });
152
- });
153
- it.each(Object.keys(schemas))('%s returns one item with filter on relational field from tables not as admin and has top level field permissions only', async (schema) => {
154
- const table = schemas[schema].tables[1];
155
- tracker.on.select(table).responseOnce(rawItems);
156
- const itemsService = new services_1.ItemsService(table, {
157
- knex: db,
158
- accountability: {
159
- role: 'admin',
160
- admin: false,
161
- permissions: [
162
- {
163
- id: 1,
164
- role: 'admin',
165
- collection: table,
166
- action: 'create',
167
- permissions: {},
168
- validation: {},
169
- presets: {},
170
- fields: ['*'],
171
- },
172
- {
173
- id: 2,
174
- role: 'admin',
175
- collection: table,
176
- action: 'read',
177
- permissions: {},
178
- validation: {},
179
- presets: {},
180
- fields: ['*'],
181
- },
182
- ],
183
- },
184
- schema: schemas[schema].schema,
185
- });
186
- const response = await itemsService.readOne(rawItems[0].id, {
187
- fields: ['id'],
188
- filter: { uploaded_by: { _in: ['b5a7dd0f-fc9f-4242-b331-83990990198f'] } },
189
- });
190
- expect(tracker.history.select.length).toBe(1);
191
- expect(tracker.history.select[0].bindings).toStrictEqual([
192
- 'b5a7dd0f-fc9f-4242-b331-83990990198f',
193
- rawItems[0].id,
194
- 100,
195
- ]);
196
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id" from "${table}" where ("${table}"."uploaded_by" in (?) and "${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
197
- expect(response).toStrictEqual({ id: rawItems[0].id });
198
- });
199
- it.each(Object.keys(schemas))('%s returns one item with filter on relational field from tables not as admin and has relational permissions', async (schema) => {
200
- const table = schemas[schema].tables[1];
201
- tracker.on.select(table).responseOnce(rawItems);
202
- const itemsService = new services_1.ItemsService(table, {
203
- knex: db,
204
- accountability: {
205
- role: 'admin',
206
- admin: false,
207
- permissions: [
208
- {
209
- id: 1,
210
- role: 'admin',
211
- collection: schemas[schema].tables[0],
212
- action: 'create',
213
- permissions: {},
214
- validation: {},
215
- presets: {},
216
- fields: ['*'],
217
- },
218
- {
219
- id: 2,
220
- role: 'admin',
221
- collection: schemas[schema].tables[1],
222
- action: 'create',
223
- permissions: {},
224
- validation: {},
225
- presets: {},
226
- fields: ['*'],
227
- },
228
- {
229
- id: 3,
230
- role: 'admin',
231
- collection: schemas[schema].tables[0],
232
- action: 'read',
233
- permissions: {},
234
- validation: {},
235
- presets: {},
236
- fields: ['*'],
237
- },
238
- {
239
- id: 4,
240
- role: 'admin',
241
- collection: schemas[schema].tables[1],
242
- action: 'read',
243
- permissions: {},
244
- validation: {},
245
- presets: {},
246
- fields: ['*'],
247
- },
248
- ],
249
- },
250
- schema: schemas[schema].schema,
251
- });
252
- const response = await itemsService.readOne(rawItems[0].id, {
253
- fields: ['id'],
254
- filter: { uploaded_by: { _in: ['b5a7dd0f-fc9f-4242-b331-83990990198f'] } },
255
- });
256
- expect(tracker.history.select.length).toBe(1);
257
- expect(tracker.history.select[0].bindings).toStrictEqual([
258
- 'b5a7dd0f-fc9f-4242-b331-83990990198f',
259
- rawItems[0].id,
260
- 100,
261
- ]);
262
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id" from "${table}" where ("${table}"."uploaded_by" in (?) and "${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
263
- expect(response).toStrictEqual({ id: rawItems[0].id });
264
- });
265
- it.each(Object.keys(schemas))('%s denies one item with filter from tables not as admin and has no field permissions', async (schema) => {
266
- let table = schemas[schema].tables[1];
267
- const item = {
268
- id: 'd66ec139-2655-48c1-9d9a-4753f98a9ee7',
269
- uploaded_by: '6107c897-9182-40f7-b22e-4f044d1258d2',
270
- };
271
- let itemsService = new services_1.ItemsService(table, {
272
- knex: db,
273
- accountability: { role: 'admin', admin: true },
274
- schema: schemas[schema].schema,
275
- });
276
- tracker.on.insert(table).responseOnce(item);
277
- await itemsService.createOne(item, { emitEvents: false });
278
- table = schemas[schema].tables[0];
279
- tracker.on.select(table).responseOnce(rawItems);
280
- itemsService = new services_1.ItemsService(table, {
281
- knex: db,
282
- accountability: {
283
- role: 'admin',
284
- admin: false,
285
- permissions: [
286
- {
287
- id: 1,
288
- role: 'admin',
289
- collection: table,
290
- action: 'create',
291
- permissions: {},
292
- validation: {},
293
- presets: {},
294
- fields: ['*'],
295
- },
296
- {
297
- id: 2,
298
- role: 'admin',
299
- collection: table,
300
- action: 'read',
301
- permissions: {},
302
- validation: {},
303
- presets: {},
304
- fields: ['id'],
305
- },
306
- ],
307
- },
308
- schema: schemas[schema].schema,
309
- });
310
- expect(() => itemsService.readOne(rawItems[0].id, { filter: { name: { _eq: 'something' } } })).rejects.toThrow("You don't have permission to access this.");
311
- expect(tracker.history.select.length).toBe(0);
312
- });
313
- it.each(Object.keys(schemas))('%s returns one item with deep filter from tables as admin', async (schema) => {
314
- const childTable = schemas[schema].tables[1];
315
- const childItems = [
316
- {
317
- id: 'd66ec139-2655-48c1-9d9a-4753f98a9ee7',
318
- title: 'A new child item',
319
- uploaded_by: 'b5a7dd0f-fc9f-4242-b331-83990990198f',
320
- },
321
- ];
322
- tracker.on.select(childTable).response(childItems);
323
- const table = schemas[schema].tables[0];
324
- tracker.on.select(table).responseOnce(rawItems);
325
- const itemsService = new services_1.ItemsService(table, {
326
- knex: db,
327
- accountability: { role: 'admin', admin: true },
328
- schema: schemas[schema].schema,
329
- });
330
- const response = await itemsService.readOne(rawItems[0].id, {
331
- fields: ['id', 'items.*'],
332
- deep: { items: { _filter: { title: { _eq: childItems[0].title } } } },
333
- });
334
- expect(tracker.history.select.length).toBe(2);
335
- expect(tracker.history.select[0].bindings).toStrictEqual([rawItems[0].id, 100]);
336
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id" from "${table}" where "${table}"."id" = ? order by "${table}"."id" asc limit ?`);
337
- expect(tracker.history.select[1].bindings).toStrictEqual([
338
- childItems[0].title,
339
- ...rawItems.map((item) => item.id),
340
- 25000,
341
- ]);
342
- expect(tracker.history.select[1].sql).toBe(`select "${childTable}"."id", "${childTable}"."title", "${childTable}"."uploaded_by" from "${childTable}" where "${childTable}"."title" = ? and "${childTable}"."uploaded_by" in (?, ?) order by "${childTable}"."id" asc limit ?`);
343
- expect(response).toStrictEqual({ id: rawItems[0].id, items: childItems });
344
- });
345
- it.each(Object.keys(schemas))('%s returns one item with deep filter from tables not as admin but has field permissions', async (schema) => {
346
- const childTable = schemas[schema].tables[1];
347
- const childItems = [
348
- {
349
- id: 'd66ec139-2655-48c1-9d9a-4753f98a9ee7',
350
- title: 'A new child item',
351
- uploaded_by: 'b5a7dd0f-fc9f-4242-b331-83990990198f',
352
- },
353
- ];
354
- tracker.on.select(childTable).response(childItems);
355
- const table = schemas[schema].tables[0];
356
- tracker.on.select(table).responseOnce(rawItems);
357
- const itemsService = new services_1.ItemsService(table, {
358
- knex: db,
359
- accountability: {
360
- role: 'admin',
361
- admin: false,
362
- permissions: [
363
- {
364
- id: 1,
365
- role: 'admin',
366
- collection: schemas[schema].tables[0],
367
- action: 'create',
368
- permissions: {},
369
- validation: {},
370
- presets: {},
371
- fields: ['*'],
372
- },
373
- {
374
- id: 2,
375
- role: 'admin',
376
- collection: schemas[schema].tables[1],
377
- action: 'create',
378
- permissions: {},
379
- validation: {},
380
- presets: {},
381
- fields: ['*'],
382
- },
383
- {
384
- id: 3,
385
- role: 'admin',
386
- collection: schemas[schema].tables[0],
387
- action: 'read',
388
- permissions: {},
389
- validation: {},
390
- presets: {},
391
- fields: ['id', 'items'],
392
- },
393
- {
394
- id: 4,
395
- role: 'admin',
396
- collection: schemas[schema].tables[1],
397
- action: 'read',
398
- permissions: {},
399
- validation: {},
400
- presets: {},
401
- fields: ['id', 'title', 'uploaded_by'],
402
- },
403
- ],
404
- },
405
- schema: schemas[schema].schema,
406
- });
407
- const response = await itemsService.readOne(rawItems[0].id, {
408
- fields: ['id', 'items.*'],
409
- deep: { items: { _filter: { title: { _eq: childItems[0].title } } } },
410
- });
411
- expect(tracker.history.select.length).toBe(2);
412
- expect(tracker.history.select[0].bindings).toStrictEqual([rawItems[0].id, 100]);
413
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id" from "${table}" where ("${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
414
- expect(tracker.history.select[1].bindings).toStrictEqual([
415
- childItems[0].title,
416
- ...rawItems.map((item) => item.id),
417
- 25000,
418
- ]);
419
- expect(tracker.history.select[1].sql).toBe(`select "${childTable}"."id", "${childTable}"."title", "${childTable}"."uploaded_by" from "${childTable}" where ("${childTable}"."title" = ?) and "${childTable}"."uploaded_by" in (?, ?) order by "${childTable}"."id" asc limit ?`);
420
- expect(response).toStrictEqual({ id: rawItems[0].id, items: childItems });
421
- });
422
- it.each(Object.keys(schemas))('%s denies one item with deep filter from tables not as admin and has no field permissions', async (schema) => {
423
- const childTable = schemas[schema].tables[1];
424
- const childItems = [
425
- {
426
- id: 'd66ec139-2655-48c1-9d9a-4753f98a9ee7',
427
- title: 'A new child item',
428
- uploaded_by: 1,
429
- },
430
- ];
431
- tracker.on.select(childTable).response(childItems);
432
- const table = schemas[schema].tables[0];
433
- tracker.on.select(table).responseOnce(rawItems);
434
- const itemsService = new services_1.ItemsService(table, {
435
- knex: db,
436
- accountability: {
437
- role: 'admin',
438
- admin: false,
439
- permissions: [
440
- {
441
- id: 1,
442
- role: 'admin',
443
- collection: schemas[schema].tables[0],
444
- action: 'create',
445
- permissions: {},
446
- validation: {},
447
- presets: {},
448
- fields: ['*'],
449
- },
450
- {
451
- id: 2,
452
- role: 'admin',
453
- collection: schemas[schema].tables[1],
454
- action: 'create',
455
- permissions: {},
456
- validation: {},
457
- presets: {},
458
- fields: ['*'],
459
- },
460
- {
461
- id: 3,
462
- role: 'admin',
463
- collection: schemas[schema].tables[0],
464
- action: 'read',
465
- permissions: {},
466
- validation: {},
467
- presets: {},
468
- fields: ['id', 'items'],
469
- },
470
- {
471
- id: 4,
472
- role: 'admin',
473
- collection: schemas[schema].tables[1],
474
- action: 'read',
475
- permissions: {},
476
- validation: {},
477
- presets: {},
478
- fields: ['id', 'uploaded_by'],
479
- },
480
- ],
481
- },
482
- schema: schemas[schema].schema,
483
- });
484
- expect(() => itemsService.readOne(rawItems[0].id, {
485
- fields: ['id', 'items.*'],
486
- deep: { items: { _filter: { title: { _eq: childItems[0].title } } } },
487
- })).rejects.toThrow("You don't have permission to access this.");
488
- expect(tracker.history.select.length).toBe(0);
489
- });
490
- it.each(Object.keys(schemas))('%s denies item from tables not as admin but collection accountability "all"', async (schema) => {
491
- const table = schemas[schema].tables[0];
492
- const customSchema = (0, lodash_1.cloneDeep)(schemas[schema].schema);
493
- customSchema.collections[table].accountability = 'all';
494
- const itemsService = new services_1.ItemsService(table, {
495
- knex: db,
496
- accountability: {
497
- role: 'admin',
498
- admin: false,
499
- },
500
- schema: customSchema,
501
- });
502
- expect(() => itemsService.readOne(rawItems[0].id)).rejects.toThrow("You don't have permission to access this.");
503
- expect(tracker.history.select.length).toBe(0);
504
- });
505
- it.each(Object.keys(schemas))('%s denies user access when permission action does not match read.', async (schema) => {
506
- const table = schemas[schema].tables[0];
507
- const itemsService = new services_1.ItemsService(table, {
508
- knex: db,
509
- accountability: {
510
- role: 'admin',
511
- admin: false,
512
- permissions: [
513
- {
514
- id: 1,
515
- role: 'admin',
516
- collection: table,
517
- action: 'create',
518
- permissions: {},
519
- validation: {},
520
- presets: {},
521
- fields: [],
522
- },
523
- ],
524
- },
525
- schema: schemas[schema].schema,
526
- });
527
- expect(() => itemsService.readOne(rawItems[0].id)).rejects.toThrow("You don't have permission to access this.");
528
- expect(tracker.history.select.length).toBe(0);
529
- });
530
- it.each(Object.keys(schemas))('%s returns count() that is processed without role permissions', async (schema) => {
531
- const childTable = schemas[schema].tables[1];
532
- const childItems = [
533
- {
534
- items_count: 1,
535
- id: rawItems[0].id,
536
- },
537
- ];
538
- tracker.on.select(childTable).response(childItems);
539
- const table = schemas[schema].tables[0];
540
- const itemsService = new services_1.ItemsService(table, {
541
- knex: db,
542
- accountability: {
543
- role: 'admin',
544
- admin: false,
545
- permissions: [
546
- {
547
- id: 1,
548
- role: 'admin',
549
- collection: schemas[schema].tables[0],
550
- action: 'read',
551
- permissions: {},
552
- validation: {},
553
- presets: {},
554
- fields: ['id', 'items'],
555
- },
556
- {
557
- id: 2,
558
- role: 'admin',
559
- collection: schemas[schema].tables[1],
560
- action: 'read',
561
- permissions: {},
562
- validation: {},
563
- presets: {},
564
- fields: ['id', 'title', 'uploaded_by'],
565
- },
566
- ],
567
- },
568
- schema: schemas[schema].schema,
569
- });
570
- const response = await itemsService.readOne(rawItems[0].id, {
571
- fields: ['count(items)'],
572
- });
573
- expect(tracker.history.select.length).toBe(1);
574
- expect(tracker.history.select[0].bindings).toStrictEqual([rawItems[0].id, 100]);
575
- expect(tracker.history.select[0].sql).toBe(`select (select count(*) from "${childTable}" where "uploaded_by" = "${table}"."id") AS "items_count", "${table}"."id" from "${table}" where ("${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
576
- expect(response).toStrictEqual({ items_count: 1 });
577
- });
578
- it.each(Object.keys(schemas))('%s returns count() that is processed with role permissions', async (schema) => {
579
- const childTable = schemas[schema].tables[1];
580
- const childItems = [
581
- {
582
- items_count: 1,
583
- id: rawItems[0].id,
584
- },
585
- ];
586
- tracker.on.select(childTable).response(childItems);
587
- const table = schemas[schema].tables[0];
588
- const itemsService = new services_1.ItemsService(table, {
589
- knex: db,
590
- accountability: {
591
- role: 'admin',
592
- admin: false,
593
- permissions: [
594
- {
595
- id: 1,
596
- role: 'admin',
597
- collection: schemas[schema].tables[0],
598
- action: 'read',
599
- permissions: {},
600
- validation: {},
601
- presets: {},
602
- fields: ['id', 'items'],
603
- },
604
- {
605
- id: 2,
606
- role: 'admin',
607
- collection: schemas[schema].tables[1],
608
- action: 'read',
609
- permissions: { _and: [{ title: { _contains: 'child' } }] },
610
- validation: {},
611
- presets: {},
612
- fields: ['id', 'title', 'uploaded_by'],
613
- },
614
- ],
615
- },
616
- schema: schemas[schema].schema,
617
- });
618
- const response = await itemsService.readOne(rawItems[0].id, {
619
- fields: ['count(items)'],
620
- });
621
- expect(tracker.history.select.length).toBe(1);
622
- expect(tracker.history.select[0].bindings).toStrictEqual([rawItems[0].id, 100]);
623
- expect(tracker.history.select[0].sql).toBe(`select (select count(*) from "${childTable}" where "uploaded_by" = "${table}"."id" and (("${childTable}"."title" like '%child%'))) AS "items_count", "${table}"."id" from "${table}" where ("${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
624
- expect(response).toStrictEqual({ items_count: 1 });
625
- });
626
- });
627
- });
628
- describe('readMany', () => {
629
- const items = [
630
- { id: 'b5a7dd0f-fc9f-4242-b331-83990990198f', name: 'string1' },
631
- { id: '6107c897-9182-40f7-b22e-4f044d1258d2', name: 'string2' },
632
- ];
633
- it.each(Object.keys(schemas))('%s it returns multiple items from tables as admin', async (schema) => {
634
- const table = schemas[schema].tables[0];
635
- tracker.on.select(table).responseOnce(items);
636
- const itemsService = new services_1.ItemsService(table, {
637
- knex: db,
638
- accountability: { role: 'admin', admin: true },
639
- schema: schemas[schema].schema,
640
- });
641
- const response = await itemsService.readMany([items[0].id, items[1].id], { fields: ['id', 'name'] });
642
- expect(tracker.history.select.length).toBe(1);
643
- expect(tracker.history.select[0].bindings).toStrictEqual([items[0].id, items[1].id, 2]);
644
- expect(tracker.history.select[0].sql).toBe(`select ${(0, items_utils_1.sqlFieldFormatter)(schemas[schema].schema, table)} from "${table}" where ("${table}"."id" in (?, ?)) order by "${table}"."id" asc limit ?`);
645
- expect(response).toStrictEqual(items);
646
- });
647
- describe('Global Query Params', () => {
648
- it.each(Object.keys(schemas))(`Filter: %s _eq`, async (schema) => {
649
- const table = schemas[schema].tables[0];
650
- tracker.on.select(table).responseOnce([items[1]]);
651
- const itemsService = new services_1.ItemsService(table, {
652
- knex: db,
653
- accountability: { role: 'admin', admin: true },
654
- schema: schemas[schema].schema,
655
- });
656
- const response = await itemsService.readMany([], {
657
- fields: ['id', 'name'],
658
- filter: { id: { _eq: items[1].id } },
659
- });
660
- expect(tracker.history.select.length).toBe(1);
661
- expect(tracker.history.select[0].bindings).toStrictEqual([0, items[1].id, 100]);
662
- expect(tracker.history.select[0].sql).toBe(`select ${(0, items_utils_1.sqlFieldFormatter)(schemas[schema].schema, table)} from "${table}" where (1 = ? and "${table}"."id" = ?) order by "${table}"."id" asc limit ?`);
663
- expect(response).toStrictEqual([items[1]]);
664
- });
665
- it.each(Object.keys(schemas))(`Filter: %s _or`, async (schema) => {
666
- const table = schemas[schema].tables[0];
667
- tracker.on.select(table).responseOnce([items[1]]);
668
- const itemsService = new services_1.ItemsService(table, {
669
- knex: db,
670
- accountability: { role: 'admin', admin: true },
671
- schema: schemas[schema].schema,
672
- });
673
- const response = await itemsService.readMany([], {
674
- fields: ['id', 'name'],
675
- filter: { _or: [{ id: { _eq: items[1].id } }, { name: { _eq: items[1].name } }] },
676
- });
677
- expect(tracker.history.select.length).toBe(1);
678
- expect(tracker.history.select[0].bindings).toStrictEqual([0, items[1].id, items[1].name, 100]);
679
- expect(tracker.history.select[0].sql).toBe(`select ${(0, items_utils_1.sqlFieldFormatter)(schemas[schema].schema, table)} from "${table}" where (1 = ? and ("${table}"."id" = ? or "${table}"."name" = ?)) order by "${table}"."id" asc limit ?`);
680
- expect(response).toStrictEqual([items[1]]);
681
- });
682
- });
683
- });
684
- describe('updateOne', () => {
685
- const item = { id: '6107c897-9182-40f7-b22e-4f044d1258d2', name: 'Item name', items: [] };
686
- it.each(Object.keys(schemas))('%s updates relational field in one item without read permissions', async (schema) => {
687
- const childTable = schemas[schema].tables[1];
688
- const childItem = {
689
- id: 'd66ec139-2655-48c1-9d9a-4753f98a9ee7',
690
- title: 'A new child item',
691
- uploaded_by: '6107c897-9182-40f7-b22e-4f044d1258d2',
692
- };
693
- tracker.on.select(childTable).response([childItem]);
694
- tracker.on.update(childTable).response(childItem);
695
- const table = schemas[schema].tables[0];
696
- schemas[schema].accountability = null;
697
- tracker.on.select(table).response([item]);
698
- const itemsService = new services_1.ItemsService(table, {
699
- knex: db,
700
- accountability: {
701
- role: 'admin',
702
- admin: false,
703
- permissions: [
704
- {
705
- id: 1,
706
- role: 'admin',
707
- collection: schemas[schema].tables[0],
708
- action: 'create',
709
- permissions: {},
710
- validation: {},
711
- presets: {},
712
- fields: ['*'],
713
- },
714
- {
715
- id: 2,
716
- role: 'admin',
717
- collection: schemas[schema].tables[1],
718
- action: 'create',
719
- permissions: {},
720
- validation: {},
721
- presets: {},
722
- fields: ['*'],
723
- },
724
- {
725
- id: 3,
726
- role: 'admin',
727
- collection: schemas[schema].tables[0],
728
- action: 'update',
729
- permissions: {},
730
- validation: {},
731
- presets: {},
732
- fields: ['*'],
733
- },
734
- {
735
- id: 4,
736
- role: 'admin',
737
- collection: schemas[schema].tables[1],
738
- action: 'update',
739
- permissions: {},
740
- validation: {},
741
- presets: {},
742
- fields: ['*'],
743
- },
744
- ],
745
- },
746
- schema: schemas[schema].schema,
747
- });
748
- const response = await itemsService.updateOne(item.id, {
749
- items: [],
750
- }, { emitEvents: false });
751
- expect(tracker.history.select.length).toBe(4);
752
- expect(tracker.history.select[0].bindings).toStrictEqual([item.id, 1]);
753
- expect(tracker.history.select[0].sql).toBe(`select "${table}"."id", "${table}"."name" from "${table}" where (("${table}"."id" in (?))) order by "${table}"."id" asc limit ?`);
754
- expect(tracker.history.select[1].bindings).toStrictEqual([item.id, 25000]);
755
- expect(tracker.history.select[1].sql).toBe(`select "${childTable}"."uploaded_by", "${childTable}"."id" from "${childTable}" where "${childTable}"."uploaded_by" in (?) order by "${childTable}"."id" asc limit ?`);
756
- expect(tracker.history.select[2].bindings).toStrictEqual([item.id, 1, 100]);
757
- expect(tracker.history.select[2].sql).toBe(`select "${childTable}"."id" from "${childTable}" where ("${childTable}"."uploaded_by" = ? and 1 = ?) order by "${childTable}"."id" asc limit ?`);
758
- expect(tracker.history.select[3].bindings).toStrictEqual([childItem.id, 1]);
759
- expect(tracker.history.select[3].sql).toBe(`select "${childTable}"."id", "${childTable}"."title", "${childTable}"."uploaded_by" from "${childTable}" where (("${childTable}"."id" in (?))) order by "${childTable}"."id" asc limit ?`);
760
- expect(tracker.history.update[0].bindings).toStrictEqual([null, childItem.id]);
761
- expect(tracker.history.update[0].sql).toBe(`update "${childTable}" set "uploaded_by" = ? where "id" in (?)`);
762
- expect(response).toStrictEqual(item.id);
763
- });
764
- });
765
- });