directus 9.10.0 → 9.12.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.
- package/dist/app.js +8 -1
- package/dist/auth/drivers/oauth2.d.ts +1 -1
- package/dist/auth/drivers/oauth2.js +14 -11
- package/dist/auth/drivers/openid.d.ts +1 -1
- package/dist/auth/drivers/openid.js +14 -11
- package/dist/cli/commands/schema/apply.js +4 -3
- package/dist/cli/utils/create-env/env-stub.liquid +266 -9
- package/dist/controllers/activity.js +1 -1
- package/dist/controllers/assets.js +8 -9
- package/dist/controllers/flows.d.ts +2 -0
- package/dist/controllers/flows.js +157 -0
- package/dist/controllers/folders.js +1 -1
- package/dist/controllers/notifications.js +1 -1
- package/dist/controllers/operations.d.ts +2 -0
- package/dist/controllers/operations.js +138 -0
- package/dist/database/helpers/date/dialects/sqlite.js +6 -2
- package/dist/database/index.js +15 -19
- package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -1
- package/dist/database/migrations/20210506A-rename-interfaces.js +2 -1
- package/dist/database/migrations/20210802A-replace-groups.js +2 -1
- package/dist/database/migrations/20210805A-update-groups.js +2 -1
- package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -2
- package/dist/database/migrations/20211007A-update-presets.js +5 -4
- package/dist/database/migrations/20220429A-add-flows.d.ts +3 -0
- package/dist/database/migrations/20220429A-add-flows.js +83 -0
- package/dist/database/migrations/20220429B-add-color-to-insights-icon.d.ts +3 -0
- package/dist/database/migrations/20220429B-add-color-to-insights-icon.js +15 -0
- package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.d.ts +3 -0
- package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.js +15 -0
- package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.d.ts +3 -0
- package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.js +15 -0
- package/dist/database/run-ast.js +10 -14
- package/dist/database/seeds/05-activity.yaml +0 -1
- package/dist/database/system-data/collections/collections.yaml +4 -0
- package/dist/database/system-data/fields/activity.yaml +3 -0
- package/dist/database/system-data/fields/dashboards.yaml +3 -1
- package/dist/database/system-data/fields/flows.yaml +21 -0
- package/dist/database/system-data/fields/notifications.yaml +3 -1
- package/dist/database/system-data/fields/operations.yaml +19 -0
- package/dist/database/system-data/fields/panels.yaml +3 -1
- package/dist/database/system-data/fields/shares.yaml +3 -1
- package/dist/database/system-data/fields/users.yaml +2 -4
- package/dist/database/system-data/relations/relations.yaml +20 -0
- package/dist/env.d.ts +1 -1
- package/dist/env.js +167 -12
- package/dist/exceptions/index.d.ts +1 -0
- package/dist/exceptions/index.js +1 -0
- package/dist/exceptions/invalid-provider.d.ts +4 -0
- package/dist/exceptions/invalid-provider.js +10 -0
- package/dist/exceptions/range-not-satisfiable.d.ts +2 -2
- package/dist/exceptions/range-not-satisfiable.js +5 -1
- package/dist/extensions.d.ts +3 -0
- package/dist/extensions.js +73 -20
- package/dist/flows.d.ts +17 -0
- package/dist/flows.js +310 -0
- package/dist/messenger.d.ts +24 -0
- package/dist/messenger.js +64 -0
- package/dist/middleware/graphql.js +2 -1
- package/dist/operations/condition/index.d.ts +6 -0
- package/dist/operations/condition/index.js +15 -0
- package/dist/operations/item-create/index.d.ts +8 -0
- package/dist/operations/item-create/index.js +40 -0
- package/dist/operations/item-delete/index.d.ts +9 -0
- package/dist/operations/item-delete/index.js +45 -0
- package/dist/operations/item-read/index.d.ts +9 -0
- package/dist/operations/item-read/index.js +45 -0
- package/dist/operations/item-update/index.d.ts +10 -0
- package/dist/operations/item-update/index.js +50 -0
- package/dist/operations/log/index.d.ts +5 -0
- package/dist/operations/log/index.js +14 -0
- package/dist/operations/mail/index.d.ts +7 -0
- package/dist/operations/mail/index.js +16 -0
- package/dist/operations/notification/index.d.ts +8 -0
- package/dist/operations/notification/index.js +39 -0
- package/dist/operations/request/index.d.ts +9 -0
- package/dist/operations/request/index.js +14 -0
- package/dist/operations/sleep/index.d.ts +5 -0
- package/dist/operations/sleep/index.js +9 -0
- package/dist/operations/transform/index.d.ts +5 -0
- package/dist/operations/transform/index.js +10 -0
- package/dist/operations/trigger/index.d.ts +6 -0
- package/dist/operations/trigger/index.js +21 -0
- package/dist/services/activity.d.ts +1 -2
- package/dist/services/activity.js +10 -10
- package/dist/services/assets.js +27 -1
- package/dist/services/authentication.d.ts +2 -2
- package/dist/services/authentication.js +11 -8
- package/dist/services/authorization.js +12 -0
- package/dist/services/fields.js +15 -8
- package/dist/services/flows.d.ts +14 -0
- package/dist/services/flows.js +42 -0
- package/dist/services/graphql.js +56 -33
- package/dist/services/import-export.d.ts +1 -1
- package/dist/services/import-export.js +13 -12
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.js +2 -0
- package/dist/services/items.d.ts +3 -3
- package/dist/services/items.js +25 -2
- package/dist/services/mail/index.js +2 -1
- package/dist/services/notifications.d.ts +2 -1
- package/dist/services/notifications.js +4 -3
- package/dist/services/operations.d.ts +14 -0
- package/dist/services/operations.js +42 -0
- package/dist/services/payload.d.ts +2 -2
- package/dist/services/payload.js +8 -7
- package/dist/services/users.d.ts +4 -0
- package/dist/services/users.js +20 -0
- package/dist/services/webhooks.d.ts +2 -0
- package/dist/services/webhooks.js +8 -7
- package/dist/types/events.d.ts +18 -0
- package/dist/types/events.js +2 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/utils/apply-query.js +31 -4
- package/dist/utils/apply-snapshot.d.ts +3 -3
- package/dist/utils/apply-snapshot.js +64 -49
- package/dist/utils/construct-flow-tree.d.ts +2 -0
- package/dist/utils/construct-flow-tree.js +31 -0
- package/dist/utils/get-accountability-for-role.d.ts +7 -0
- package/dist/utils/get-accountability-for-role.js +36 -0
- package/dist/utils/get-ast-from-query.js +1 -7
- package/dist/utils/get-default-value.js +4 -3
- package/dist/utils/get-permissions.d.ts +1 -1
- package/dist/utils/get-permissions.js +9 -8
- package/dist/utils/get-schema.js +2 -1
- package/dist/utils/get-snapshot.js +22 -4
- package/dist/utils/operation-options.d.ts +3 -0
- package/dist/utils/operation-options.js +45 -0
- package/dist/utils/parse-json.d.ts +5 -0
- package/dist/utils/parse-json.js +19 -0
- package/dist/utils/sanitize-query.d.ts +1 -2
- package/dist/utils/sanitize-query.js +6 -5
- package/dist/utils/validate-keys.d.ts +6 -0
- package/dist/utils/validate-keys.js +28 -0
- package/dist/utils/validate-query.js +1 -1
- package/dist/webhooks.d.ts +2 -0
- package/dist/webhooks.js +17 -2
- package/package.json +18 -14
- package/dist/types/activity.d.ts +0 -9
- package/dist/types/activity.js +0 -13
- package/example.env +0 -202
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WebhooksService = void 0;
|
|
4
|
-
const webhooks_1 = require("../webhooks");
|
|
5
4
|
const items_1 = require("./items");
|
|
5
|
+
const messenger_1 = require("../messenger");
|
|
6
6
|
class WebhooksService extends items_1.ItemsService {
|
|
7
7
|
constructor(options) {
|
|
8
8
|
super('directus_webhooks', options);
|
|
9
|
+
this.messenger = (0, messenger_1.getMessenger)();
|
|
9
10
|
}
|
|
10
11
|
async createOne(data, opts) {
|
|
11
12
|
const result = await super.createOne(data, opts);
|
|
12
|
-
|
|
13
|
+
this.messenger.publish('webhooks', { type: 'reload' });
|
|
13
14
|
return result;
|
|
14
15
|
}
|
|
15
16
|
async createMany(data, opts) {
|
|
16
17
|
const result = await super.createMany(data, opts);
|
|
17
|
-
|
|
18
|
+
this.messenger.publish('webhooks', { type: 'reload' });
|
|
18
19
|
return result;
|
|
19
20
|
}
|
|
20
21
|
async updateOne(key, data, opts) {
|
|
21
22
|
const result = await super.updateOne(key, data, opts);
|
|
22
|
-
|
|
23
|
+
this.messenger.publish('webhooks', { type: 'reload' });
|
|
23
24
|
return result;
|
|
24
25
|
}
|
|
25
26
|
async updateMany(keys, data, opts) {
|
|
26
27
|
const result = await super.updateMany(keys, data, opts);
|
|
27
|
-
|
|
28
|
+
this.messenger.publish('webhooks', { type: 'reload' });
|
|
28
29
|
return result;
|
|
29
30
|
}
|
|
30
31
|
async deleteOne(key, opts) {
|
|
31
32
|
const result = await super.deleteOne(key, opts);
|
|
32
|
-
|
|
33
|
+
this.messenger.publish('webhooks', { type: 'reload' });
|
|
33
34
|
return result;
|
|
34
35
|
}
|
|
35
36
|
async deleteMany(keys, opts) {
|
|
36
37
|
const result = await super.deleteMany(keys, opts);
|
|
37
|
-
|
|
38
|
+
this.messenger.publish('webhooks', { type: 'reload' });
|
|
38
39
|
return result;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ActionHandler, FilterHandler, InitHandler } from '@directus/shared/types';
|
|
2
|
+
import { ScheduledTask } from 'node-cron';
|
|
3
|
+
export declare type EventHandler = {
|
|
4
|
+
type: 'filter';
|
|
5
|
+
name: string;
|
|
6
|
+
handler: FilterHandler;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'action';
|
|
9
|
+
name: string;
|
|
10
|
+
handler: ActionHandler;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'init';
|
|
13
|
+
name: string;
|
|
14
|
+
handler: InitHandler;
|
|
15
|
+
} | {
|
|
16
|
+
type: 'schedule';
|
|
17
|
+
task: ScheduledTask;
|
|
18
|
+
};
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED
|
@@ -10,11 +10,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
10
10
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./activity"), exports);
|
|
14
13
|
__exportStar(require("./assets"), exports);
|
|
15
14
|
__exportStar(require("./ast"), exports);
|
|
16
15
|
__exportStar(require("./auth"), exports);
|
|
17
16
|
__exportStar(require("./collection"), exports);
|
|
17
|
+
__exportStar(require("./events"), exports);
|
|
18
18
|
__exportStar(require("./files"), exports);
|
|
19
19
|
__exportStar(require("./graphql"), exports);
|
|
20
20
|
__exportStar(require("./items"), exports);
|
|
@@ -4,15 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.applyAggregate = exports.applySearch = exports.applyFilter = exports.applySort = void 0;
|
|
7
|
-
const utils_1 = require("@directus/shared/utils");
|
|
8
7
|
const lodash_1 = require("lodash");
|
|
9
8
|
const nanoid_1 = require("nanoid");
|
|
10
9
|
const uuid_validate_1 = __importDefault(require("uuid-validate"));
|
|
11
10
|
const helpers_1 = require("../database/helpers");
|
|
12
|
-
const
|
|
11
|
+
const invalid_query_1 = require("../exceptions/invalid-query");
|
|
13
12
|
const get_column_1 = require("./get-column");
|
|
14
13
|
const get_column_path_1 = require("./get-column-path");
|
|
15
14
|
const get_relation_info_1 = require("./get-relation-info");
|
|
15
|
+
const utils_1 = require("@directus/shared/utils");
|
|
16
16
|
const generateAlias = (0, nanoid_1.customAlphabet)('abcdefghijklmnopqrstuvwxyz', 5);
|
|
17
17
|
/**
|
|
18
18
|
* Apply the Query to a given Knex query builder instance
|
|
@@ -65,7 +65,7 @@ function addJoin({ path, collection, aliasMap, rootQuery, subQuery, schema, rela
|
|
|
65
65
|
if (relationType === 'a2o') {
|
|
66
66
|
const pathScope = pathParts[0].split(':')[1];
|
|
67
67
|
if (!pathScope) {
|
|
68
|
-
throw new
|
|
68
|
+
throw new invalid_query_1.InvalidQueryException(`You have to provide a collection scope when sorting or filtering on a many-to-any item`);
|
|
69
69
|
}
|
|
70
70
|
rootQuery.leftJoin({ [alias]: pathScope }, (joinClause) => {
|
|
71
71
|
joinClause
|
|
@@ -92,7 +92,7 @@ function addJoin({ path, collection, aliasMap, rootQuery, subQuery, schema, rela
|
|
|
92
92
|
else if (relationType === 'a2o') {
|
|
93
93
|
const pathScope = pathParts[0].split(':')[1];
|
|
94
94
|
if (!pathScope) {
|
|
95
|
-
throw new
|
|
95
|
+
throw new invalid_query_1.InvalidQueryException(`You have to provide a collection scope when sorting or filtering on a many-to-any item`);
|
|
96
96
|
}
|
|
97
97
|
parent = pathScope;
|
|
98
98
|
}
|
|
@@ -314,24 +314,48 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
|
|
|
314
314
|
if (operator === '_neq') {
|
|
315
315
|
dbQuery[logical].whereNot(selectionRaw, compareValue);
|
|
316
316
|
}
|
|
317
|
+
if (operator === '_ieq') {
|
|
318
|
+
dbQuery[logical].whereRaw(`LOWER(??) = ?`, [selectionRaw, `${compareValue.toLowerCase()}`]);
|
|
319
|
+
}
|
|
320
|
+
if (operator === '_nieq') {
|
|
321
|
+
dbQuery[logical].whereRaw(`LOWER(??) <> ?`, [selectionRaw, `${compareValue.toLowerCase()}`]);
|
|
322
|
+
}
|
|
317
323
|
if (operator === '_contains') {
|
|
318
324
|
dbQuery[logical].where(selectionRaw, 'like', `%${compareValue}%`);
|
|
319
325
|
}
|
|
320
326
|
if (operator === '_ncontains') {
|
|
321
327
|
dbQuery[logical].whereNot(selectionRaw, 'like', `%${compareValue}%`);
|
|
322
328
|
}
|
|
329
|
+
if (operator === '_icontains') {
|
|
330
|
+
dbQuery[logical].whereRaw(`LOWER(??) LIKE ?`, [selectionRaw, `%${compareValue.toLowerCase()}%`]);
|
|
331
|
+
}
|
|
332
|
+
if (operator === '_nicontains') {
|
|
333
|
+
dbQuery[logical].whereRaw(`LOWER(??) NOT LIKE ?`, [selectionRaw, `%${compareValue.toLowerCase()}%`]);
|
|
334
|
+
}
|
|
323
335
|
if (operator === '_starts_with') {
|
|
324
336
|
dbQuery[logical].where(key, 'like', `${compareValue}%`);
|
|
325
337
|
}
|
|
326
338
|
if (operator === '_nstarts_with') {
|
|
327
339
|
dbQuery[logical].whereNot(key, 'like', `${compareValue}%`);
|
|
328
340
|
}
|
|
341
|
+
if (operator === '_istarts_with') {
|
|
342
|
+
dbQuery[logical].whereRaw(`LOWER(??) LIKE ?`, [selectionRaw, `${compareValue.toLowerCase()}%`]);
|
|
343
|
+
}
|
|
344
|
+
if (operator === '_nistarts_with') {
|
|
345
|
+
dbQuery[logical].whereRaw(`LOWER(??) NOT LIKE ?`, [selectionRaw, `${compareValue.toLowerCase()}%`]);
|
|
346
|
+
}
|
|
329
347
|
if (operator === '_ends_with') {
|
|
330
348
|
dbQuery[logical].where(key, 'like', `%${compareValue}`);
|
|
331
349
|
}
|
|
332
350
|
if (operator === '_nends_with') {
|
|
333
351
|
dbQuery[logical].whereNot(key, 'like', `%${compareValue}`);
|
|
334
352
|
}
|
|
353
|
+
if (operator === '_iends_with') {
|
|
354
|
+
dbQuery[logical].whereRaw(`LOWER(??) LIKE ?`, [selectionRaw, `%${compareValue.toLowerCase()}`]);
|
|
355
|
+
}
|
|
356
|
+
if (operator === '_niends_with') {
|
|
357
|
+
dbQuery[logical].whereRaw(`LOWER(??) NOT LIKE ?`, [selectionRaw, `%${compareValue.toLowerCase()}`]);
|
|
358
|
+
}
|
|
335
359
|
if (operator === '_gt') {
|
|
336
360
|
dbQuery[logical].where(selectionRaw, '>', compareValue);
|
|
337
361
|
}
|
|
@@ -418,6 +442,9 @@ function applyAggregate(dbQuery, aggregate, collection) {
|
|
|
418
442
|
if (operation === 'avgDistinct') {
|
|
419
443
|
dbQuery.avgDistinct(`${collection}.${field}`, { as: `avgDistinct->${field}` });
|
|
420
444
|
}
|
|
445
|
+
if (operation === 'countAll') {
|
|
446
|
+
dbQuery.count('*', { as: 'countAll' });
|
|
447
|
+
}
|
|
421
448
|
if (operation === 'count') {
|
|
422
449
|
if (field === '*') {
|
|
423
450
|
dbQuery.count('*', { as: 'count' });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Snapshot, SnapshotDiff, SnapshotField } from '../types';
|
|
2
|
-
import { Knex } from 'knex';
|
|
3
|
-
import { Diff } from 'deep-diff';
|
|
4
1
|
import { SchemaOverview } from '@directus/shared/types';
|
|
2
|
+
import { Diff } from 'deep-diff';
|
|
3
|
+
import { Knex } from 'knex';
|
|
4
|
+
import { Snapshot, SnapshotDiff, SnapshotField } from '../types';
|
|
5
5
|
export declare function applySnapshot(snapshot: Snapshot, options?: {
|
|
6
6
|
database?: Knex;
|
|
7
7
|
schema?: SchemaOverview;
|
|
@@ -4,13 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.isNestedMetaUpdate = exports.applySnapshot = void 0;
|
|
7
|
-
const get_snapshot_1 = require("./get-snapshot");
|
|
8
|
-
const get_snapshot_diff_1 = require("./get-snapshot-diff");
|
|
9
|
-
const database_1 = __importDefault(require("../database"));
|
|
10
|
-
const get_schema_1 = require("./get-schema");
|
|
11
|
-
const services_1 = require("../services");
|
|
12
7
|
const lodash_1 = require("lodash");
|
|
8
|
+
const database_1 = __importDefault(require("../database"));
|
|
13
9
|
const logger_1 = __importDefault(require("../logger"));
|
|
10
|
+
const services_1 = require("../services");
|
|
11
|
+
const get_schema_1 = require("./get-schema");
|
|
12
|
+
const get_snapshot_1 = require("./get-snapshot");
|
|
13
|
+
const get_snapshot_diff_1 = require("./get-snapshot-diff");
|
|
14
14
|
async function applySnapshot(snapshot, options) {
|
|
15
15
|
var _a, _b, _c, _d;
|
|
16
16
|
const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
|
|
@@ -19,55 +19,70 @@ async function applySnapshot(snapshot, options) {
|
|
|
19
19
|
const snapshotDiff = (_d = options === null || options === void 0 ? void 0 : options.diff) !== null && _d !== void 0 ? _d : (0, get_snapshot_diff_1.getSnapshotDiff)(current, snapshot);
|
|
20
20
|
await database.transaction(async (trx) => {
|
|
21
21
|
const collectionsService = new services_1.CollectionsService({ knex: trx, schema });
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
const getNestedCollectionsToCreate = (currentLevelCollection) => snapshotDiff.collections.filter(({ diff }) => { var _a, _b; return ((_b = (_a = diff[0].rhs) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.group) === currentLevelCollection; });
|
|
23
|
+
const getNestedCollectionsToDelete = (currentLevelCollection) => snapshotDiff.collections.filter(({ diff }) => { var _a, _b; return ((_b = (_a = diff[0].lhs) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.group) === currentLevelCollection; });
|
|
24
|
+
const createCollections = async (collections) => {
|
|
25
|
+
for (const { collection, diff } of collections) {
|
|
26
|
+
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N' && diff[0].rhs) {
|
|
27
|
+
// We'll nest the to-be-created fields in the same collection creation, to prevent
|
|
28
|
+
// creating a collection without a primary key
|
|
29
|
+
const fields = snapshotDiff.fields
|
|
30
|
+
.filter((fieldDiff) => fieldDiff.collection === collection)
|
|
31
|
+
.map((fieldDiff) => fieldDiff.diff[0].rhs)
|
|
32
|
+
.map((fieldDiff) => {
|
|
33
|
+
// Casts field type to UUID when applying SQLite-based schema on other databases.
|
|
34
|
+
// This is needed because SQLite snapshots UUID fields as char with length 36, and
|
|
35
|
+
// it will fail when trying to create relation between char field to UUID field
|
|
36
|
+
if (!fieldDiff.schema ||
|
|
37
|
+
fieldDiff.schema.data_type !== 'char' ||
|
|
38
|
+
fieldDiff.schema.max_length !== 36 ||
|
|
39
|
+
!fieldDiff.schema.foreign_key_table ||
|
|
40
|
+
!fieldDiff.schema.foreign_key_column) {
|
|
41
|
+
return fieldDiff;
|
|
42
|
+
}
|
|
43
|
+
const matchingForeignKeyTable = schema.collections[fieldDiff.schema.foreign_key_table];
|
|
44
|
+
if (!matchingForeignKeyTable)
|
|
45
|
+
return fieldDiff;
|
|
46
|
+
const matchingForeignKeyField = matchingForeignKeyTable.fields[fieldDiff.schema.foreign_key_column];
|
|
47
|
+
if (!matchingForeignKeyField || matchingForeignKeyField.type !== 'uuid')
|
|
48
|
+
return fieldDiff;
|
|
49
|
+
return (0, lodash_1.merge)(fieldDiff, { type: 'uuid', schema: { data_type: 'uuid', max_length: null } });
|
|
50
|
+
});
|
|
51
|
+
try {
|
|
52
|
+
await collectionsService.createOne({
|
|
53
|
+
...diff[0].rhs,
|
|
54
|
+
fields,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
logger_1.default.error(`Failed to create collection "${collection}"`);
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
// Now that the fields are in for this collection, we can strip them from the field edits
|
|
62
|
+
snapshotDiff.fields = snapshotDiff.fields.filter((fieldDiff) => fieldDiff.collection !== collection);
|
|
63
|
+
await createCollections(getNestedCollectionsToCreate(collection));
|
|
30
64
|
}
|
|
31
65
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
fieldDiff.schema.data_type !== 'char' ||
|
|
44
|
-
fieldDiff.schema.max_length !== 36 ||
|
|
45
|
-
!fieldDiff.schema.foreign_key_table ||
|
|
46
|
-
!fieldDiff.schema.foreign_key_column) {
|
|
47
|
-
return fieldDiff;
|
|
66
|
+
};
|
|
67
|
+
const deleteCollections = async (collections) => {
|
|
68
|
+
for (const { collection, diff } of collections) {
|
|
69
|
+
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
|
|
70
|
+
await deleteCollections(getNestedCollectionsToDelete(collection));
|
|
71
|
+
try {
|
|
72
|
+
await collectionsService.deleteOne(collection);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
logger_1.default.error(`Failed to delete collection "${collection}"`);
|
|
76
|
+
throw err;
|
|
48
77
|
}
|
|
49
|
-
const matchingForeignKeyTable = schema.collections[fieldDiff.schema.foreign_key_table];
|
|
50
|
-
if (!matchingForeignKeyTable)
|
|
51
|
-
return fieldDiff;
|
|
52
|
-
const matchingForeignKeyField = matchingForeignKeyTable.fields[fieldDiff.schema.foreign_key_column];
|
|
53
|
-
if (!matchingForeignKeyField || matchingForeignKeyField.type !== 'uuid')
|
|
54
|
-
return fieldDiff;
|
|
55
|
-
return (0, lodash_1.merge)(fieldDiff, { type: 'uuid', schema: { data_type: 'uuid', max_length: null } });
|
|
56
|
-
});
|
|
57
|
-
try {
|
|
58
|
-
await collectionsService.createOne({
|
|
59
|
-
...diff[0].rhs,
|
|
60
|
-
fields,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
logger_1.default.error(`Failed to create collection "${collection}"`);
|
|
65
|
-
throw err;
|
|
66
78
|
}
|
|
67
|
-
// Now that the fields are in for this collection, we can strip them from the field
|
|
68
|
-
// edits
|
|
69
|
-
snapshotDiff.fields = snapshotDiff.fields.filter((fieldDiff) => fieldDiff.collection !== collection);
|
|
70
79
|
}
|
|
80
|
+
};
|
|
81
|
+
// create top level collections (no group) first, then continue with nested collections recursively
|
|
82
|
+
await createCollections(snapshotDiff.collections.filter(({ diff }) => { var _a; return diff[0].kind === 'N' && ((_a = diff[0].rhs.meta) === null || _a === void 0 ? void 0 : _a.group) === null; }));
|
|
83
|
+
// delete top level collections (no group) first, then continue with nested collections recursively
|
|
84
|
+
await deleteCollections(snapshotDiff.collections.filter(({ diff }) => { var _a; return diff[0].kind === 'D' && ((_a = diff[0].lhs.meta) === null || _a === void 0 ? void 0 : _a.group) === null; }));
|
|
85
|
+
for (const { collection, diff } of snapshotDiff.collections) {
|
|
71
86
|
if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'E' || (diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'A') {
|
|
72
87
|
const newValues = snapshot.collections.find((field) => {
|
|
73
88
|
return field.collection === collection;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.constructFlowTree = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
function constructFlowTree(flow) {
|
|
6
|
+
var _a;
|
|
7
|
+
const rootOperation = (_a = flow.operations.find((operation) => operation.id === flow.operation)) !== null && _a !== void 0 ? _a : null;
|
|
8
|
+
const operationTree = constructOperationTree(rootOperation, flow.operations);
|
|
9
|
+
const flowTree = {
|
|
10
|
+
...(0, lodash_1.omit)(flow, 'operations'),
|
|
11
|
+
operation: operationTree,
|
|
12
|
+
};
|
|
13
|
+
return flowTree;
|
|
14
|
+
}
|
|
15
|
+
exports.constructFlowTree = constructFlowTree;
|
|
16
|
+
function constructOperationTree(root, operations) {
|
|
17
|
+
if (root === null) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const resolveOperation = root.resolve !== null ? operations.find((operation) => operation.id === root.resolve) : null;
|
|
21
|
+
const rejectOperation = root.reject !== null ? operations.find((operation) => operation.id === root.reject) : null;
|
|
22
|
+
if (resolveOperation === undefined || rejectOperation === undefined) {
|
|
23
|
+
throw new Error('Undefined reference in operations');
|
|
24
|
+
}
|
|
25
|
+
const operationTree = {
|
|
26
|
+
...(0, lodash_1.omit)(root, 'flow'),
|
|
27
|
+
resolve: constructOperationTree(resolveOperation, operations),
|
|
28
|
+
reject: constructOperationTree(rejectOperation, operations),
|
|
29
|
+
};
|
|
30
|
+
return operationTree;
|
|
31
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Accountability, SchemaOverview } from '@directus/shared/types';
|
|
2
|
+
import { Knex } from 'knex';
|
|
3
|
+
export declare function getAccountabilityForRole(role: null | string, context: {
|
|
4
|
+
accountability: null | Accountability;
|
|
5
|
+
schema: SchemaOverview;
|
|
6
|
+
database: Knex;
|
|
7
|
+
}): Promise<Accountability>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAccountabilityForRole = void 0;
|
|
4
|
+
const get_permissions_1 = require("./get-permissions");
|
|
5
|
+
const exceptions_1 = require("../exceptions");
|
|
6
|
+
async function getAccountabilityForRole(role, context) {
|
|
7
|
+
let generatedAccountability = context.accountability;
|
|
8
|
+
if (role === null) {
|
|
9
|
+
generatedAccountability = {
|
|
10
|
+
role: null,
|
|
11
|
+
user: null,
|
|
12
|
+
admin: false,
|
|
13
|
+
app: false,
|
|
14
|
+
};
|
|
15
|
+
generatedAccountability.permissions = await (0, get_permissions_1.getPermissions)(generatedAccountability, context.schema);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const roleInfo = await context.database
|
|
19
|
+
.select(['app_access', 'admin_access'])
|
|
20
|
+
.from('directus_roles')
|
|
21
|
+
.where({ id: role })
|
|
22
|
+
.first();
|
|
23
|
+
if (!roleInfo) {
|
|
24
|
+
throw new exceptions_1.InvalidConfigException(`Configured role "${role}" isn't a valid role ID or doesn't exist.`);
|
|
25
|
+
}
|
|
26
|
+
generatedAccountability = {
|
|
27
|
+
role,
|
|
28
|
+
user: null,
|
|
29
|
+
admin: roleInfo.admin_access === 1 || roleInfo.admin_access === '1' || roleInfo.admin_access === true,
|
|
30
|
+
app: roleInfo.app_access === 1 || roleInfo.app_access === '1' || roleInfo.app_access === true,
|
|
31
|
+
};
|
|
32
|
+
generatedAccountability.permissions = await (0, get_permissions_1.getPermissions)(generatedAccountability, context.schema);
|
|
33
|
+
}
|
|
34
|
+
return generatedAccountability;
|
|
35
|
+
}
|
|
36
|
+
exports.getAccountabilityForRole = getAccountabilityForRole;
|
|
@@ -80,12 +80,6 @@ async function getASTFromQuery(collection, query, schema, options) {
|
|
|
80
80
|
if (name in query.alias) {
|
|
81
81
|
name = query.alias[fieldKey];
|
|
82
82
|
}
|
|
83
|
-
// check for junction alias (it is one of the value instead of the key)
|
|
84
|
-
if (Object.values(query.alias).includes(name)) {
|
|
85
|
-
const aliasKey = Object.keys(query.alias).find((key) => { var _a; return ((_a = query.alias) === null || _a === void 0 ? void 0 : _a[key]) === name; });
|
|
86
|
-
if (aliasKey && fieldKey !== aliasKey)
|
|
87
|
-
name = aliasKey;
|
|
88
|
-
}
|
|
89
83
|
}
|
|
90
84
|
const isRelational = name.includes('.') ||
|
|
91
85
|
// We'll always treat top level o2m fields as a related item. This is an alias field, otherwise it won't return
|
|
@@ -93,7 +87,7 @@ async function getASTFromQuery(collection, query, schema, options) {
|
|
|
93
87
|
!!schema.relations.find((relation) => { var _a; return relation.related_collection === parentCollection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field) === name; });
|
|
94
88
|
if (isRelational) {
|
|
95
89
|
// field is relational
|
|
96
|
-
const parts =
|
|
90
|
+
const parts = fieldKey.split('.');
|
|
97
91
|
let rootField = parts[0];
|
|
98
92
|
let collectionScope = null;
|
|
99
93
|
// a2o related collection scoped field selector `fields=sections.section_id:headings.title`
|
|
@@ -3,9 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const get_local_type_1 = __importDefault(require("./get-local-type"));
|
|
7
|
-
const logger_1 = __importDefault(require("../logger"));
|
|
8
6
|
const env_1 = __importDefault(require("../env"));
|
|
7
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
8
|
+
const get_local_type_1 = __importDefault(require("./get-local-type"));
|
|
9
|
+
const parse_json_1 = require("./parse-json");
|
|
9
10
|
function getDefaultValue(column) {
|
|
10
11
|
var _a;
|
|
11
12
|
const type = (0, get_local_type_1.default)(column);
|
|
@@ -59,7 +60,7 @@ function castToObject(value) {
|
|
|
59
60
|
return value;
|
|
60
61
|
if (typeof value === 'string') {
|
|
61
62
|
try {
|
|
62
|
-
return
|
|
63
|
+
return (0, parse_json_1.parseJSON)(value);
|
|
63
64
|
}
|
|
64
65
|
catch (err) {
|
|
65
66
|
if (env_1.default.NODE_ENV === 'development') {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Accountability, Permission, SchemaOverview } from '@directus/shared/types';
|
|
2
2
|
export declare function getPermissions(accountability: Accountability, schema: SchemaOverview): Promise<Permission[]>;
|
|
@@ -6,15 +6,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getPermissions = void 0;
|
|
7
7
|
const utils_1 = require("@directus/shared/utils");
|
|
8
8
|
const lodash_1 = require("lodash");
|
|
9
|
+
const object_hash_1 = __importDefault(require("object-hash"));
|
|
10
|
+
const cache_1 = require("../cache");
|
|
9
11
|
const database_1 = __importDefault(require("../database"));
|
|
10
12
|
const app_access_permissions_1 = require("../database/system-data/app-access-permissions");
|
|
13
|
+
const env_1 = __importDefault(require("../env"));
|
|
14
|
+
const roles_1 = require("../services/roles");
|
|
15
|
+
const users_1 = require("../services/users");
|
|
11
16
|
const merge_permissions_1 = require("../utils/merge-permissions");
|
|
12
17
|
const merge_permissions_for_share_1 = require("./merge-permissions-for-share");
|
|
13
|
-
const
|
|
14
|
-
const roles_1 = require("../services/roles");
|
|
15
|
-
const cache_1 = require("../cache");
|
|
16
|
-
const object_hash_1 = __importDefault(require("object-hash"));
|
|
17
|
-
const env_1 = __importDefault(require("../env"));
|
|
18
|
+
const parse_json_1 = require("./parse-json");
|
|
18
19
|
async function getPermissions(accountability, schema) {
|
|
19
20
|
const database = (0, database_1.default)();
|
|
20
21
|
const { systemCache, cache } = (0, cache_1.getCache)();
|
|
@@ -84,19 +85,19 @@ function parsePermissions(permissions) {
|
|
|
84
85
|
permissions = permissions.map((permissionRaw) => {
|
|
85
86
|
const permission = (0, lodash_1.cloneDeep)(permissionRaw);
|
|
86
87
|
if (permission.permissions && typeof permission.permissions === 'string') {
|
|
87
|
-
permission.permissions =
|
|
88
|
+
permission.permissions = (0, parse_json_1.parseJSON)(permission.permissions);
|
|
88
89
|
}
|
|
89
90
|
else if (permission.permissions === null) {
|
|
90
91
|
permission.permissions = {};
|
|
91
92
|
}
|
|
92
93
|
if (permission.validation && typeof permission.validation === 'string') {
|
|
93
|
-
permission.validation =
|
|
94
|
+
permission.validation = (0, parse_json_1.parseJSON)(permission.validation);
|
|
94
95
|
}
|
|
95
96
|
else if (permission.validation === null) {
|
|
96
97
|
permission.validation = {};
|
|
97
98
|
}
|
|
98
99
|
if (permission.presets && typeof permission.presets === 'string') {
|
|
99
|
-
permission.presets =
|
|
100
|
+
permission.presets = (0, parse_json_1.parseJSON)(permission.presets);
|
|
100
101
|
}
|
|
101
102
|
else if (permission.presets === null) {
|
|
102
103
|
permission.presets = {};
|
package/dist/utils/get-schema.js
CHANGED
|
@@ -17,6 +17,7 @@ const logger_1 = __importDefault(require("../logger"));
|
|
|
17
17
|
const services_1 = require("../services");
|
|
18
18
|
const get_default_value_1 = __importDefault(require("./get-default-value"));
|
|
19
19
|
const get_local_type_1 = __importDefault(require("./get-local-type"));
|
|
20
|
+
const parse_json_1 = require("./parse-json");
|
|
20
21
|
async function getSchema(options) {
|
|
21
22
|
const database = (options === null || options === void 0 ? void 0 : options.database) || (0, database_1.default)();
|
|
22
23
|
const schemaInspector = (0, schema_1.default)(database);
|
|
@@ -119,7 +120,7 @@ async function getDatabaseSchema(database, schemaInspector) {
|
|
|
119
120
|
const type = (existing && (0, get_local_type_1.default)(column, { special })) || 'alias';
|
|
120
121
|
let validation = (_a = field.validation) !== null && _a !== void 0 ? _a : null;
|
|
121
122
|
if (validation && typeof validation === 'string')
|
|
122
|
-
validation =
|
|
123
|
+
validation = (0, parse_json_1.parseJSON)(validation);
|
|
123
124
|
result.collections[field.collection].fields[field.field] = {
|
|
124
125
|
field: field.field,
|
|
125
126
|
defaultValue: (_b = existing === null || existing === void 0 ? void 0 : existing.defaultValue) !== null && _b !== void 0 ? _b : null,
|
|
@@ -16,17 +16,23 @@ async function getSnapshot(options) {
|
|
|
16
16
|
const collectionsService = new services_1.CollectionsService({ knex: database, schema });
|
|
17
17
|
const fieldsService = new services_1.FieldsService({ knex: database, schema });
|
|
18
18
|
const relationsService = new services_1.RelationsService({ knex: database, schema });
|
|
19
|
-
const [
|
|
19
|
+
const [collectionsRaw, fieldsRaw, relationsRaw] = await Promise.all([
|
|
20
20
|
collectionsService.readByQuery(),
|
|
21
21
|
fieldsService.readAll(),
|
|
22
22
|
relationsService.readAll(),
|
|
23
23
|
]);
|
|
24
|
+
const collectionsFiltered = collectionsRaw.filter((item) => excludeSystem(item));
|
|
25
|
+
const fieldsFiltered = fieldsRaw.filter((item) => excludeSystem(item)).map(omitID);
|
|
26
|
+
const relationsFiltered = relationsRaw.filter((item) => excludeSystem(item)).map(omitID);
|
|
27
|
+
const collectionsSorted = (0, lodash_1.sortBy)((0, lodash_1.mapValues)(collectionsFiltered, sortDeep), ['collection']);
|
|
28
|
+
const fieldsSorted = (0, lodash_1.sortBy)((0, lodash_1.mapValues)(fieldsFiltered, sortDeep), ['collection', 'field']);
|
|
29
|
+
const relationsSorted = (0, lodash_1.sortBy)((0, lodash_1.mapValues)(relationsFiltered, sortDeep), ['collection', 'field']);
|
|
24
30
|
return {
|
|
25
31
|
version: 1,
|
|
26
32
|
directus: package_json_1.version,
|
|
27
|
-
collections:
|
|
28
|
-
fields:
|
|
29
|
-
relations:
|
|
33
|
+
collections: collectionsSorted,
|
|
34
|
+
fields: fieldsSorted,
|
|
35
|
+
relations: relationsSorted,
|
|
30
36
|
};
|
|
31
37
|
}
|
|
32
38
|
exports.getSnapshot = getSnapshot;
|
|
@@ -39,3 +45,15 @@ function excludeSystem(item) {
|
|
|
39
45
|
function omitID(item) {
|
|
40
46
|
return (0, lodash_1.omit)(item, 'meta.id');
|
|
41
47
|
}
|
|
48
|
+
function sortDeep(raw) {
|
|
49
|
+
if ((0, lodash_1.isPlainObject)(raw)) {
|
|
50
|
+
const mapped = (0, lodash_1.mapValues)(raw, sortDeep);
|
|
51
|
+
const pairs = (0, lodash_1.toPairs)(mapped);
|
|
52
|
+
const sorted = (0, lodash_1.sortBy)(pairs);
|
|
53
|
+
return (0, lodash_1.fromPairs)(sorted);
|
|
54
|
+
}
|
|
55
|
+
if ((0, lodash_1.isArray)(raw)) {
|
|
56
|
+
return (0, lodash_1.sortBy)(raw);
|
|
57
|
+
}
|
|
58
|
+
return raw;
|
|
59
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.optionToString = exports.optionToObject = exports.applyOperationOptions = void 0;
|
|
4
|
+
const micromustache_1 = require("micromustache");
|
|
5
|
+
const parse_json_1 = require("./parse-json");
|
|
6
|
+
function resolveFn(path, scope) {
|
|
7
|
+
if (!scope)
|
|
8
|
+
return undefined;
|
|
9
|
+
const value = (0, micromustache_1.get)(scope, path);
|
|
10
|
+
return typeof value === 'object' ? JSON.stringify(value) : value;
|
|
11
|
+
}
|
|
12
|
+
function renderMustache(item, scope) {
|
|
13
|
+
if (typeof item === 'string') {
|
|
14
|
+
return (0, micromustache_1.renderFn)(item, resolveFn, scope, { explicit: true });
|
|
15
|
+
}
|
|
16
|
+
else if (Array.isArray(item)) {
|
|
17
|
+
return item.map((element) => renderMustache(element, scope));
|
|
18
|
+
}
|
|
19
|
+
else if (typeof item === 'object' && item !== null) {
|
|
20
|
+
return Object.fromEntries(Object.entries(item).map(([key, value]) => [key, renderMustache(value, scope)]));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return item;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function applyOperationOptions(options, data) {
|
|
27
|
+
return Object.fromEntries(Object.entries(options).map(([key, value]) => {
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
const single = value.match(/^\{\{\s*([^}\s]+)\s*\}\}$/);
|
|
30
|
+
if (single !== null) {
|
|
31
|
+
return [key, (0, micromustache_1.get)(data, single[1])];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return [key, renderMustache(value, data)];
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
exports.applyOperationOptions = applyOperationOptions;
|
|
38
|
+
function optionToObject(option) {
|
|
39
|
+
return typeof option === 'string' ? (0, parse_json_1.parseJSON)(option) : option;
|
|
40
|
+
}
|
|
41
|
+
exports.optionToObject = optionToObject;
|
|
42
|
+
function optionToString(option) {
|
|
43
|
+
return typeof option === 'object' ? JSON.stringify(option) : String(option);
|
|
44
|
+
}
|
|
45
|
+
exports.optionToString = optionToString;
|