directus 9.2.1 → 9.4.1
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 +5 -3
- package/dist/auth/auth.d.ts +4 -6
- package/dist/auth/auth.js +5 -9
- package/dist/auth/drivers/ldap.d.ts +3 -3
- package/dist/auth/drivers/ldap.js +6 -2
- package/dist/auth/drivers/local.d.ts +2 -2
- package/dist/auth/drivers/local.js +5 -12
- package/dist/auth/drivers/oauth2.d.ts +3 -3
- package/dist/auth/drivers/oauth2.js +2 -3
- package/dist/auth/drivers/openid.d.ts +3 -3
- package/dist/auth/drivers/openid.js +2 -3
- package/dist/cli/commands/bootstrap/index.js +3 -2
- package/dist/cli/commands/init/index.js +3 -7
- package/dist/cli/commands/schema/apply.js +1 -1
- package/dist/cli/utils/defaults.d.ts +11 -0
- package/dist/cli/utils/defaults.js +14 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.js +16 -2
- package/dist/controllers/shares.d.ts +2 -0
- package/dist/controllers/shares.js +212 -0
- package/dist/controllers/users.js +21 -9
- package/dist/database/migrations/20211211A-add-shares.d.ts +3 -0
- package/dist/database/migrations/20211211A-add-shares.js +38 -0
- package/dist/database/run-ast.js +5 -5
- package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -15
- package/dist/database/system-data/app-access-permissions/index.d.ts +1 -0
- package/dist/database/system-data/app-access-permissions/index.js +4 -2
- package/dist/database/system-data/app-access-permissions/schema-access-permissions.yaml +17 -0
- package/dist/database/system-data/collections/collections.yaml +3 -0
- package/dist/database/system-data/fields/_defaults.yaml +2 -0
- package/dist/database/system-data/fields/sessions.yaml +1 -1
- package/dist/database/system-data/fields/settings.yaml +9 -0
- package/dist/database/system-data/fields/shares.yaml +77 -0
- package/dist/database/system-data/fields/users.yaml +1 -1
- package/dist/database/system-data/relations/relations.yaml +15 -0
- package/dist/emitter.d.ts +3 -2
- package/dist/emitter.js +13 -6
- package/dist/env.js +1 -1
- package/dist/exceptions/index.d.ts +1 -0
- package/dist/exceptions/index.js +1 -0
- package/dist/exceptions/unexpected-response.d.ts +4 -0
- package/dist/exceptions/unexpected-response.js +10 -0
- package/dist/extensions.d.ts +1 -0
- package/dist/extensions.js +10 -4
- package/dist/middleware/authenticate.js +5 -15
- package/dist/middleware/check-ip.js +9 -6
- package/dist/middleware/respond.js +4 -1
- package/dist/services/activity.d.ts +2 -1
- package/dist/services/activity.js +2 -2
- package/dist/services/authentication.d.ts +2 -7
- package/dist/services/authentication.js +81 -41
- package/dist/services/authorization.js +3 -3
- package/dist/services/collections.d.ts +1 -2
- package/dist/services/collections.js +2 -2
- package/dist/services/files.d.ts +2 -2
- package/dist/services/files.js +14 -8
- package/dist/services/graphql.js +20 -5
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/items.d.ts +1 -15
- package/dist/services/notifications.d.ts +2 -2
- package/dist/services/permissions.d.ts +2 -2
- package/dist/services/roles.d.ts +2 -2
- package/dist/services/shares.d.ts +17 -0
- package/dist/services/shares.js +135 -0
- package/dist/services/specifications.js +1 -1
- package/dist/services/users.d.ts +2 -2
- package/dist/services/users.js +8 -6
- package/dist/services/webhooks.d.ts +2 -2
- package/dist/tests/database/migrations/run.test.d.ts +1 -0
- package/dist/tests/database/migrations/run.test.js +29 -0
- package/dist/types/ast.d.ts +3 -3
- package/dist/types/auth.d.ts +31 -0
- package/dist/types/extensions.d.ts +2 -0
- package/dist/types/items.d.ts +14 -0
- package/dist/utils/apply-query.d.ts +0 -38
- package/dist/utils/apply-query.js +66 -67
- package/dist/utils/apply-snapshot.js +69 -14
- package/dist/utils/get-ast-from-query.js +3 -3
- package/dist/utils/get-default-value.js +3 -1
- package/dist/utils/get-permissions.d.ts +2 -2
- package/dist/utils/get-permissions.js +117 -72
- package/dist/utils/get-relation-type.d.ts +1 -1
- package/dist/utils/get-relation-type.js +1 -1
- package/dist/utils/merge-permissions-for-share.d.ts +5 -0
- package/dist/utils/merge-permissions-for-share.js +116 -0
- package/dist/utils/merge-permissions.d.ts +13 -1
- package/dist/utils/merge-permissions.js +27 -19
- package/dist/utils/reduce-schema.d.ts +2 -2
- package/dist/utils/reduce-schema.js +7 -7
- package/dist/utils/user-name.js +3 -0
- package/example.env +1 -1
- package/package.json +14 -13
|
@@ -62,8 +62,20 @@ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
62
62
|
router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
|
|
63
63
|
router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
|
|
64
64
|
router.get('/me', (0, async_handler_1.default)(async (req, res, next) => {
|
|
65
|
-
var _a;
|
|
66
|
-
if (
|
|
65
|
+
var _a, _b, _c;
|
|
66
|
+
if ((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.share_scope) {
|
|
67
|
+
const user = {
|
|
68
|
+
share: (_b = req.accountability) === null || _b === void 0 ? void 0 : _b.share,
|
|
69
|
+
role: {
|
|
70
|
+
id: req.accountability.role,
|
|
71
|
+
admin_access: false,
|
|
72
|
+
app_access: false,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
res.locals.payload = { data: user };
|
|
76
|
+
return next();
|
|
77
|
+
}
|
|
78
|
+
if (!((_c = req.accountability) === null || _c === void 0 ? void 0 : _c.user)) {
|
|
67
79
|
throw new exceptions_1.InvalidCredentialsException();
|
|
68
80
|
}
|
|
69
81
|
const service = new services_1.UsersService({
|
|
@@ -108,7 +120,7 @@ router.patch('/me', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
108
120
|
res.locals.payload = { data: item || null };
|
|
109
121
|
return next();
|
|
110
122
|
}), respond_1.respond);
|
|
111
|
-
router.patch('/me/track/page', (0, async_handler_1.default)(async (req,
|
|
123
|
+
router.patch('/me/track/page', (0, async_handler_1.default)(async (req, _res, next) => {
|
|
112
124
|
var _a;
|
|
113
125
|
if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
|
|
114
126
|
throw new exceptions_1.InvalidCredentialsException();
|
|
@@ -162,7 +174,7 @@ router.patch('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
162
174
|
}
|
|
163
175
|
return next();
|
|
164
176
|
}), respond_1.respond);
|
|
165
|
-
router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_handler_1.default)(async (req,
|
|
177
|
+
router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_handler_1.default)(async (req, _res, next) => {
|
|
166
178
|
const service = new services_1.UsersService({
|
|
167
179
|
accountability: req.accountability,
|
|
168
180
|
schema: req.schema,
|
|
@@ -178,7 +190,7 @@ router.delete('/', (0, validate_batch_1.validateBatch)('delete'), (0, async_hand
|
|
|
178
190
|
}
|
|
179
191
|
return next();
|
|
180
192
|
}), respond_1.respond);
|
|
181
|
-
router.delete('/:pk', (0, async_handler_1.default)(async (req,
|
|
193
|
+
router.delete('/:pk', (0, async_handler_1.default)(async (req, _res, next) => {
|
|
182
194
|
const service = new services_1.UsersService({
|
|
183
195
|
accountability: req.accountability,
|
|
184
196
|
schema: req.schema,
|
|
@@ -191,7 +203,7 @@ const inviteSchema = joi_1.default.object({
|
|
|
191
203
|
role: joi_1.default.string().uuid({ version: 'uuidv4' }).required(),
|
|
192
204
|
invite_url: joi_1.default.string().uri(),
|
|
193
205
|
});
|
|
194
|
-
router.post('/invite', (0, async_handler_1.default)(async (req,
|
|
206
|
+
router.post('/invite', (0, async_handler_1.default)(async (req, _res, next) => {
|
|
195
207
|
const { error } = inviteSchema.validate(req.body);
|
|
196
208
|
if (error)
|
|
197
209
|
throw new exceptions_1.InvalidPayloadException(error.message);
|
|
@@ -206,7 +218,7 @@ const acceptInviteSchema = joi_1.default.object({
|
|
|
206
218
|
token: joi_1.default.string().required(),
|
|
207
219
|
password: joi_1.default.string().required(),
|
|
208
220
|
});
|
|
209
|
-
router.post('/invite/accept', (0, async_handler_1.default)(async (req,
|
|
221
|
+
router.post('/invite/accept', (0, async_handler_1.default)(async (req, _res, next) => {
|
|
210
222
|
const { error } = acceptInviteSchema.validate(req.body);
|
|
211
223
|
if (error)
|
|
212
224
|
throw new exceptions_1.InvalidPayloadException(error.message);
|
|
@@ -238,7 +250,7 @@ router.post('/me/tfa/generate/', (0, async_handler_1.default)(async (req, res, n
|
|
|
238
250
|
res.locals.payload = { data: { secret, otpauth_url: url } };
|
|
239
251
|
return next();
|
|
240
252
|
}), respond_1.respond);
|
|
241
|
-
router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req,
|
|
253
|
+
router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, _res, next) => {
|
|
242
254
|
var _a;
|
|
243
255
|
if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
|
|
244
256
|
throw new exceptions_1.InvalidCredentialsException();
|
|
@@ -256,7 +268,7 @@ router.post('/me/tfa/enable/', (0, async_handler_1.default)(async (req, res, nex
|
|
|
256
268
|
await service.enableTFA(req.accountability.user, req.body.otp, req.body.secret);
|
|
257
269
|
return next();
|
|
258
270
|
}), respond_1.respond);
|
|
259
|
-
router.post('/me/tfa/disable', (0, async_handler_1.default)(async (req,
|
|
271
|
+
router.post('/me/tfa/disable', (0, async_handler_1.default)(async (req, _res, next) => {
|
|
260
272
|
var _a;
|
|
261
273
|
if (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
|
|
262
274
|
throw new exceptions_1.InvalidCredentialsException();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.down = exports.up = void 0;
|
|
4
|
+
async function up(knex) {
|
|
5
|
+
await knex.schema.createTable('directus_shares', (table) => {
|
|
6
|
+
table.uuid('id').primary();
|
|
7
|
+
table.string('name');
|
|
8
|
+
table.string('collection', 64).references('collection').inTable('directus_collections').onDelete('CASCADE');
|
|
9
|
+
table.string('item');
|
|
10
|
+
table.uuid('role').references('id').inTable('directus_roles').onDelete('CASCADE');
|
|
11
|
+
table.string('password');
|
|
12
|
+
table.uuid('user_created').references('id').inTable('directus_users').onDelete('SET NULL');
|
|
13
|
+
table.timestamp('date_created').defaultTo(knex.fn.now());
|
|
14
|
+
// This was changed after the migration went live to retroactively fix mysql5, see #10693
|
|
15
|
+
table.timestamp('date_start').nullable().defaultTo(null);
|
|
16
|
+
table.timestamp('date_end').nullable().defaultTo(null);
|
|
17
|
+
table.integer('times_used').defaultTo(0);
|
|
18
|
+
table.integer('max_uses');
|
|
19
|
+
});
|
|
20
|
+
await knex.schema.alterTable('directus_sessions', (table) => {
|
|
21
|
+
table.dropColumn('data');
|
|
22
|
+
});
|
|
23
|
+
await knex.schema.alterTable('directus_sessions', (table) => {
|
|
24
|
+
table.uuid('user').nullable().alter();
|
|
25
|
+
table.uuid('share').references('id').inTable('directus_shares').onDelete('CASCADE');
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
exports.up = up;
|
|
29
|
+
async function down(knex) {
|
|
30
|
+
await knex.schema.alterTable('directus_sessions', (table) => {
|
|
31
|
+
table.uuid('user').notNullable().alter();
|
|
32
|
+
table.json('data');
|
|
33
|
+
table.dropForeign('share');
|
|
34
|
+
table.dropColumn('share');
|
|
35
|
+
});
|
|
36
|
+
await knex.schema.dropTable('directus_shares');
|
|
37
|
+
}
|
|
38
|
+
exports.down = down;
|
package/dist/database/run-ast.js
CHANGED
|
@@ -18,7 +18,7 @@ const helpers_1 = require("../database/helpers");
|
|
|
18
18
|
async function runAST(originalAST, schema, options) {
|
|
19
19
|
const ast = (0, lodash_1.cloneDeep)(originalAST);
|
|
20
20
|
const knex = (options === null || options === void 0 ? void 0 : options.knex) || (0, _1.default)();
|
|
21
|
-
if (ast.type === '
|
|
21
|
+
if (ast.type === 'a2o') {
|
|
22
22
|
const results = {};
|
|
23
23
|
for (const collection of ast.names) {
|
|
24
24
|
results[collection] = await run(collection, ast.children[collection], ast.query[collection]);
|
|
@@ -85,7 +85,7 @@ async function parseCurrentLevel(schema, collection, children, query) {
|
|
|
85
85
|
if (child.type === 'm2o') {
|
|
86
86
|
columnsToSelectInternal.push(child.fieldKey);
|
|
87
87
|
}
|
|
88
|
-
if (child.type === '
|
|
88
|
+
if (child.type === 'a2o') {
|
|
89
89
|
columnsToSelectInternal.push(child.relation.field);
|
|
90
90
|
columnsToSelectInternal.push(child.relation.meta.one_collection_field);
|
|
91
91
|
}
|
|
@@ -182,7 +182,7 @@ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
|
|
|
182
182
|
nestedNode.query.union = [foreignField, foreignIds];
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
else if (nestedNode.type === '
|
|
185
|
+
else if (nestedNode.type === 'a2o') {
|
|
186
186
|
const keysPerCollection = {};
|
|
187
187
|
for (const parentItem of parentItems) {
|
|
188
188
|
const collection = parentItem[nestedNode.relation.meta.one_collection_field];
|
|
@@ -256,7 +256,7 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
|
|
|
256
256
|
parentItem[nestedNode.fieldKey] = itemChildren.length > 0 ? itemChildren : [];
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
-
else if (nestedNode.type === '
|
|
259
|
+
else if (nestedNode.type === 'a2o') {
|
|
260
260
|
for (const parentItem of parentItems) {
|
|
261
261
|
if (!((_a = nestedNode.relation.meta) === null || _a === void 0 ? void 0 : _a.one_collection_field)) {
|
|
262
262
|
parentItem[nestedNode.fieldKey] = null;
|
|
@@ -279,7 +279,7 @@ function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem
|
|
|
279
279
|
var _a;
|
|
280
280
|
const rawItems = (0, lodash_1.cloneDeep)((0, utils_1.toArray)(rawItem));
|
|
281
281
|
const items = [];
|
|
282
|
-
if (ast.type === '
|
|
282
|
+
if (ast.type === 'a2o') {
|
|
283
283
|
const fields = {};
|
|
284
284
|
const nestedCollectionNodes = {};
|
|
285
285
|
for (const relatedCollection of ast.names) {
|
|
@@ -13,18 +13,6 @@
|
|
|
13
13
|
comment:
|
|
14
14
|
_nnull: true
|
|
15
15
|
|
|
16
|
-
- collection: directus_collections
|
|
17
|
-
action: read
|
|
18
|
-
|
|
19
|
-
- collection: directus_fields
|
|
20
|
-
action: read
|
|
21
|
-
|
|
22
|
-
- collection: directus_permissions
|
|
23
|
-
action: read
|
|
24
|
-
permissions:
|
|
25
|
-
role:
|
|
26
|
-
_eq: $CURRENT_ROLE
|
|
27
|
-
|
|
28
16
|
- collection: directus_presets
|
|
29
17
|
action: read
|
|
30
18
|
permissions:
|
|
@@ -60,9 +48,6 @@
|
|
|
60
48
|
user:
|
|
61
49
|
_eq: $CURRENT_USER
|
|
62
50
|
|
|
63
|
-
- collection: directus_relations
|
|
64
|
-
action: read
|
|
65
|
-
|
|
66
51
|
- collection: directus_roles
|
|
67
52
|
action: read
|
|
68
53
|
permissions:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.appAccessMinimalPermissions = void 0;
|
|
3
|
+
exports.appAccessMinimalPermissions = exports.schemaPermissions = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const require_yaml_1 = require("../../../utils/require-yaml");
|
|
6
6
|
const defaults = {
|
|
@@ -11,5 +11,7 @@ const defaults = {
|
|
|
11
11
|
fields: ['*'],
|
|
12
12
|
system: true,
|
|
13
13
|
};
|
|
14
|
+
const schemaPermissionsRaw = (0, require_yaml_1.requireYAML)(require.resolve('./schema-access-permissions.yaml'));
|
|
14
15
|
const permissions = (0, require_yaml_1.requireYAML)(require.resolve('./app-access-permissions.yaml'));
|
|
15
|
-
exports.
|
|
16
|
+
exports.schemaPermissions = schemaPermissionsRaw.map((row) => (0, lodash_1.merge)({}, defaults, row));
|
|
17
|
+
exports.appAccessMinimalPermissions = [...exports.schemaPermissions, ...permissions].map((row) => (0, lodash_1.merge)({}, defaults, row));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# NOTE: Activity/collections/fields/presets/relations/revisions will have an extra hardcoded filter
|
|
2
|
+
# to filter out collections you don't have read access
|
|
3
|
+
|
|
4
|
+
- collection: directus_collections
|
|
5
|
+
action: read
|
|
6
|
+
|
|
7
|
+
- collection: directus_fields
|
|
8
|
+
action: read
|
|
9
|
+
|
|
10
|
+
- collection: directus_permissions
|
|
11
|
+
action: read
|
|
12
|
+
permissions:
|
|
13
|
+
role:
|
|
14
|
+
_eq: $CURRENT_ROLE
|
|
15
|
+
|
|
16
|
+
- collection: directus_relations
|
|
17
|
+
action: read
|
|
@@ -343,3 +343,12 @@ fields:
|
|
|
343
343
|
type:
|
|
344
344
|
_neq: 'raster'
|
|
345
345
|
hidden: true
|
|
346
|
+
- field: attribution
|
|
347
|
+
name: $t:fields.directus_settings.attribution
|
|
348
|
+
type: string
|
|
349
|
+
schema:
|
|
350
|
+
is_nullable: true
|
|
351
|
+
meta:
|
|
352
|
+
interface: input
|
|
353
|
+
options:
|
|
354
|
+
placeholder: $t:fields.directus_settings.attribution_placeholder
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
table: directus_shares
|
|
2
|
+
|
|
3
|
+
fields:
|
|
4
|
+
- field: id
|
|
5
|
+
special: uuid
|
|
6
|
+
readonly: true
|
|
7
|
+
hidden: true
|
|
8
|
+
|
|
9
|
+
- field: name
|
|
10
|
+
|
|
11
|
+
- field: collection
|
|
12
|
+
width: half
|
|
13
|
+
hidden: true
|
|
14
|
+
|
|
15
|
+
- field: item
|
|
16
|
+
width: half
|
|
17
|
+
hidden: true
|
|
18
|
+
|
|
19
|
+
- field: role
|
|
20
|
+
interface: select-dropdown-m2o
|
|
21
|
+
width: half
|
|
22
|
+
options:
|
|
23
|
+
template: '{{name}}'
|
|
24
|
+
filter:
|
|
25
|
+
admin_access:
|
|
26
|
+
_eq: false
|
|
27
|
+
|
|
28
|
+
- field: password
|
|
29
|
+
special: hash,conceal
|
|
30
|
+
interface: input-hash
|
|
31
|
+
options:
|
|
32
|
+
iconRight: lock
|
|
33
|
+
masked: true
|
|
34
|
+
width: half
|
|
35
|
+
note: $t:shared_leave_blank_for_unlimited
|
|
36
|
+
|
|
37
|
+
- field: date_start
|
|
38
|
+
width: half
|
|
39
|
+
note: $t:shared_leave_blank_for_unlimited
|
|
40
|
+
|
|
41
|
+
- field: date_end
|
|
42
|
+
width: half
|
|
43
|
+
note: $t:shared_leave_blank_for_unlimited
|
|
44
|
+
|
|
45
|
+
- field: max_uses
|
|
46
|
+
width: half
|
|
47
|
+
note: $t:shared_leave_blank_for_unlimited
|
|
48
|
+
|
|
49
|
+
- field: times_used
|
|
50
|
+
width: half
|
|
51
|
+
readonly: true
|
|
52
|
+
|
|
53
|
+
- field: date_created
|
|
54
|
+
special: date-created
|
|
55
|
+
width: half
|
|
56
|
+
readonly: true
|
|
57
|
+
conditions:
|
|
58
|
+
- name: notCreatedYet
|
|
59
|
+
rule:
|
|
60
|
+
id:
|
|
61
|
+
_null: true
|
|
62
|
+
hidden: true
|
|
63
|
+
|
|
64
|
+
- field: user_created
|
|
65
|
+
special: user-created
|
|
66
|
+
interface: select-dropdown-m2o
|
|
67
|
+
width: half
|
|
68
|
+
display: user
|
|
69
|
+
options:
|
|
70
|
+
template: '{{avatar.$thumbnail}} {{first_name}} {{last_name}}'
|
|
71
|
+
readonly: true
|
|
72
|
+
conditions:
|
|
73
|
+
- name: notCreatedYet
|
|
74
|
+
rule:
|
|
75
|
+
id:
|
|
76
|
+
_null: true
|
|
77
|
+
hidden: true
|
|
@@ -12,6 +12,9 @@ defaults:
|
|
|
12
12
|
sort_field: null
|
|
13
13
|
|
|
14
14
|
data:
|
|
15
|
+
- many_collection: directus_collections
|
|
16
|
+
many_field: group
|
|
17
|
+
one_collection: directus_collections
|
|
15
18
|
- many_collection: directus_users
|
|
16
19
|
many_field: role
|
|
17
20
|
one_collection: directus_roles
|
|
@@ -73,6 +76,9 @@ data:
|
|
|
73
76
|
- many_collection: directus_sessions
|
|
74
77
|
many_field: user
|
|
75
78
|
one_collection: directus_users
|
|
79
|
+
- many_collection: directus_sessions
|
|
80
|
+
many_field: share
|
|
81
|
+
one_collection: directus_shares
|
|
76
82
|
- many_collection: directus_settings
|
|
77
83
|
many_field: storage_default_folder
|
|
78
84
|
one_collection: directus_folders
|
|
@@ -88,3 +94,12 @@ data:
|
|
|
88
94
|
- many_collection: directus_notifications
|
|
89
95
|
many_field: sender
|
|
90
96
|
one_collection: directus_users
|
|
97
|
+
- many_collection: directus_shares
|
|
98
|
+
many_field: role
|
|
99
|
+
one_collection: directus_roles
|
|
100
|
+
- many_collection: directus_shares
|
|
101
|
+
many_field: collection
|
|
102
|
+
one_collection: directus_collections
|
|
103
|
+
- many_collection: directus_shares
|
|
104
|
+
many_field: user_created
|
|
105
|
+
one_collection: directus_users
|
package/dist/emitter.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ActionHandler, FilterHandler, HookContext, InitHandler } from './types';
|
|
2
|
-
declare class Emitter {
|
|
2
|
+
export declare class Emitter {
|
|
3
3
|
private filterEmitter;
|
|
4
4
|
private actionEmitter;
|
|
5
5
|
private initEmitter;
|
|
6
6
|
constructor();
|
|
7
|
-
eventsToEmit(event: string, meta: Record<string, any>): string[];
|
|
8
7
|
emitFilter<T>(event: string, payload: T, meta: Record<string, any>, context: HookContext): Promise<T>;
|
|
9
8
|
emitAction(event: string, meta: Record<string, any>, context: HookContext): void;
|
|
10
9
|
emitInit(event: string, meta: Record<string, any>): Promise<void>;
|
|
@@ -14,6 +13,8 @@ declare class Emitter {
|
|
|
14
13
|
offFilter(event: string, handler: FilterHandler): void;
|
|
15
14
|
offAction(event: string, handler: ActionHandler): void;
|
|
16
15
|
offInit(event: string, handler: InitHandler): void;
|
|
16
|
+
offAll(): void;
|
|
17
|
+
private eventsToEmit;
|
|
17
18
|
}
|
|
18
19
|
declare const emitter: Emitter;
|
|
19
20
|
export default emitter;
|
package/dist/emitter.js
CHANGED
|
@@ -3,6 +3,7 @@ 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
|
+
exports.Emitter = void 0;
|
|
6
7
|
const eventemitter2_1 = require("eventemitter2");
|
|
7
8
|
const logger_1 = __importDefault(require("./logger"));
|
|
8
9
|
class Emitter {
|
|
@@ -18,12 +19,6 @@ class Emitter {
|
|
|
18
19
|
this.actionEmitter = new eventemitter2_1.EventEmitter2(emitterOptions);
|
|
19
20
|
this.initEmitter = new eventemitter2_1.EventEmitter2(emitterOptions);
|
|
20
21
|
}
|
|
21
|
-
eventsToEmit(event, meta) {
|
|
22
|
-
if (event.startsWith('items')) {
|
|
23
|
-
return [event, `${meta.collection}.${event}`];
|
|
24
|
-
}
|
|
25
|
-
return [event];
|
|
26
|
-
}
|
|
27
22
|
async emitFilter(event, payload, meta, context) {
|
|
28
23
|
const events = this.eventsToEmit(event, meta);
|
|
29
24
|
const listeners = events.flatMap((event) => this.filterEmitter.listeners(event));
|
|
@@ -72,6 +67,18 @@ class Emitter {
|
|
|
72
67
|
offInit(event, handler) {
|
|
73
68
|
this.initEmitter.off(event, handler);
|
|
74
69
|
}
|
|
70
|
+
offAll() {
|
|
71
|
+
this.filterEmitter.removeAllListeners();
|
|
72
|
+
this.actionEmitter.removeAllListeners();
|
|
73
|
+
this.initEmitter.removeAllListeners();
|
|
74
|
+
}
|
|
75
|
+
eventsToEmit(event, meta) {
|
|
76
|
+
if (event.startsWith('items')) {
|
|
77
|
+
return [event, `${meta.collection}.${event}`];
|
|
78
|
+
}
|
|
79
|
+
return [event];
|
|
80
|
+
}
|
|
75
81
|
}
|
|
82
|
+
exports.Emitter = Emitter;
|
|
76
83
|
const emitter = new Emitter();
|
|
77
84
|
exports.default = emitter;
|
package/dist/env.js
CHANGED
|
@@ -20,7 +20,7 @@ const defaults = {
|
|
|
20
20
|
PORT: 8055,
|
|
21
21
|
PUBLIC_URL: '/',
|
|
22
22
|
MAX_PAYLOAD_SIZE: '100kb',
|
|
23
|
-
DB_EXCLUDE_TABLES: 'spatial_ref_sys',
|
|
23
|
+
DB_EXCLUDE_TABLES: 'spatial_ref_sys,sysdiagrams',
|
|
24
24
|
STORAGE_LOCATIONS: 'local',
|
|
25
25
|
STORAGE_LOCAL_DRIVER: 'local',
|
|
26
26
|
STORAGE_LOCAL_ROOT: './uploads',
|
package/dist/exceptions/index.js
CHANGED
|
@@ -27,3 +27,4 @@ __exportStar(require("./route-not-found"), exports);
|
|
|
27
27
|
__exportStar(require("./service-unavailable"), exports);
|
|
28
28
|
__exportStar(require("./unprocessable-entity"), exports);
|
|
29
29
|
__exportStar(require("./user-suspended"), exports);
|
|
30
|
+
__exportStar(require("./unexpected-response"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnexpectedResponseException = void 0;
|
|
4
|
+
const exceptions_1 = require("@directus/shared/exceptions");
|
|
5
|
+
class UnexpectedResponseException extends exceptions_1.BaseException {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message, 503, 'UNEXPECTED_RESPONSE');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.UnexpectedResponseException = UnexpectedResponseException;
|
package/dist/extensions.d.ts
CHANGED
package/dist/extensions.js
CHANGED
|
@@ -28,7 +28,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
28
28
|
const node_1 = require("@directus/shared/utils/node");
|
|
29
29
|
const constants_1 = require("@directus/shared/constants");
|
|
30
30
|
const database_1 = __importDefault(require("./database"));
|
|
31
|
-
const emitter_1 =
|
|
31
|
+
const emitter_1 = __importStar(require("./emitter"));
|
|
32
32
|
const env_1 = __importDefault(require("./env"));
|
|
33
33
|
const exceptions = __importStar(require("./exceptions"));
|
|
34
34
|
const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
|
|
@@ -44,6 +44,7 @@ const plugin_virtual_1 = __importDefault(require("@rollup/plugin-virtual"));
|
|
|
44
44
|
const plugin_alias_1 = __importDefault(require("@rollup/plugin-alias"));
|
|
45
45
|
const url_1 = require("./utils/url");
|
|
46
46
|
const get_module_default_1 = __importDefault(require("./utils/get-module-default"));
|
|
47
|
+
const lodash_1 = require("lodash");
|
|
47
48
|
let extensionManager;
|
|
48
49
|
function getExtensionManager() {
|
|
49
50
|
if (extensionManager) {
|
|
@@ -61,6 +62,7 @@ class ExtensionManager {
|
|
|
61
62
|
this.apiHooks = [];
|
|
62
63
|
this.apiEndpoints = [];
|
|
63
64
|
this.isScheduleHookEnabled = true;
|
|
65
|
+
this.apiEmitter = new emitter_1.Emitter();
|
|
64
66
|
this.endpointRouter = (0, express_1.Router)();
|
|
65
67
|
}
|
|
66
68
|
async initialize({ schedule } = { schedule: true }) {
|
|
@@ -92,6 +94,7 @@ class ExtensionManager {
|
|
|
92
94
|
logger_1.default.info('Reloading extensions');
|
|
93
95
|
this.unregisterHooks();
|
|
94
96
|
this.unregisterEndpoints();
|
|
97
|
+
this.apiEmitter.offAll();
|
|
95
98
|
if (env_1.default.SERVE_APP) {
|
|
96
99
|
this.appExtensions = {};
|
|
97
100
|
}
|
|
@@ -139,12 +142,13 @@ class ExtensionManager {
|
|
|
139
142
|
return bundles;
|
|
140
143
|
}
|
|
141
144
|
async getSharedDepsMapping(deps) {
|
|
142
|
-
const appDir = await fs_extra_1.default.readdir(path_1.default.join((0, node_1.resolvePackage)('@directus/app'), 'dist'));
|
|
145
|
+
const appDir = await fs_extra_1.default.readdir(path_1.default.join((0, node_1.resolvePackage)('@directus/app'), 'dist', 'assets'));
|
|
143
146
|
const depsMapping = {};
|
|
144
147
|
for (const dep of deps) {
|
|
145
|
-
const
|
|
148
|
+
const depRegex = new RegExp(`${(0, lodash_1.escapeRegExp)(dep.replace(/\//g, '_'))}\\.[0-9a-f]{8}\\.entry\\.js`);
|
|
149
|
+
const depName = appDir.find((file) => depRegex.test(file));
|
|
146
150
|
if (depName) {
|
|
147
|
-
const depUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', depName);
|
|
151
|
+
const depUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', 'assets', depName);
|
|
148
152
|
depsMapping[dep] = depUrl.toString({ rootRelative: true });
|
|
149
153
|
}
|
|
150
154
|
else {
|
|
@@ -237,6 +241,7 @@ class ExtensionManager {
|
|
|
237
241
|
exceptions: { ...exceptions, ...sharedExceptions },
|
|
238
242
|
env: env_1.default,
|
|
239
243
|
database: (0, database_1.default)(),
|
|
244
|
+
emitter: this.apiEmitter,
|
|
240
245
|
logger: logger_1.default,
|
|
241
246
|
getSchema: get_schema_1.getSchema,
|
|
242
247
|
});
|
|
@@ -254,6 +259,7 @@ class ExtensionManager {
|
|
|
254
259
|
exceptions: { ...exceptions, ...sharedExceptions },
|
|
255
260
|
env: env_1.default,
|
|
256
261
|
database: (0, database_1.default)(),
|
|
262
|
+
emitter: this.apiEmitter,
|
|
257
263
|
logger: logger_1.default,
|
|
258
264
|
getSchema: get_schema_1.getSchema,
|
|
259
265
|
});
|
|
@@ -58,22 +58,12 @@ const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
58
58
|
throw err;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.from('directus_users')
|
|
64
|
-
.leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id')
|
|
65
|
-
.where({
|
|
66
|
-
'directus_users.id': payload.id,
|
|
67
|
-
status: 'active',
|
|
68
|
-
})
|
|
69
|
-
.first();
|
|
70
|
-
if (!user) {
|
|
71
|
-
throw new exceptions_1.InvalidCredentialsException();
|
|
72
|
-
}
|
|
61
|
+
req.accountability.share = payload.share;
|
|
62
|
+
req.accountability.share_scope = payload.share_scope;
|
|
73
63
|
req.accountability.user = payload.id;
|
|
74
|
-
req.accountability.role =
|
|
75
|
-
req.accountability.admin =
|
|
76
|
-
req.accountability.app =
|
|
64
|
+
req.accountability.role = payload.role;
|
|
65
|
+
req.accountability.admin = payload.admin_access === true || payload.admin_access == 1;
|
|
66
|
+
req.accountability.app = payload.app_access === true || payload.app_access == 1;
|
|
77
67
|
}
|
|
78
68
|
else {
|
|
79
69
|
// Try finding the user with the provided token
|
|
@@ -7,13 +7,16 @@ exports.checkIP = void 0;
|
|
|
7
7
|
const database_1 = __importDefault(require("../database"));
|
|
8
8
|
const exceptions_1 = require("../exceptions");
|
|
9
9
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
10
|
-
exports.checkIP = (0, async_handler_1.default)(async (req,
|
|
10
|
+
exports.checkIP = (0, async_handler_1.default)(async (req, _res, next) => {
|
|
11
11
|
const database = (0, database_1.default)();
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
.
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
const query = database.select('ip_access').from('directus_roles');
|
|
13
|
+
if (req.accountability.role) {
|
|
14
|
+
query.where({ id: req.accountability.role });
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
query.whereNull('id');
|
|
18
|
+
}
|
|
19
|
+
const role = await query.first();
|
|
17
20
|
const ipAllowlist = ((role === null || role === void 0 ? void 0 : role.ip_access) || '').split(',').filter((ip) => ip);
|
|
18
21
|
if (ipAllowlist.length > 0 && ipAllowlist.includes(req.accountability.ip) === false)
|
|
19
22
|
throw new exceptions_1.InvalidIPException();
|
|
@@ -77,9 +77,12 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
|
77
77
|
if (Buffer.isBuffer(res.locals.payload)) {
|
|
78
78
|
return res.end(res.locals.payload);
|
|
79
79
|
}
|
|
80
|
-
else {
|
|
80
|
+
else if (res.locals.payload) {
|
|
81
81
|
return res.json(res.locals.payload);
|
|
82
82
|
}
|
|
83
|
+
else {
|
|
84
|
+
return res.status(204).end();
|
|
85
|
+
}
|
|
83
86
|
});
|
|
84
87
|
function getDateFormatted() {
|
|
85
88
|
const date = new Date();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AbstractServiceOptions, PrimaryKey, Item } from '../types';
|
|
2
|
-
import { ItemsService
|
|
2
|
+
import { ItemsService } from './items';
|
|
3
|
+
import { MutationOptions } from '../types';
|
|
3
4
|
import { NotificationsService } from './notifications';
|
|
4
5
|
import { UsersService } from './users';
|
|
5
6
|
export declare class ActivityService extends ItemsService {
|