directus 9.2.0 → 9.4.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 (90) hide show
  1. package/dist/app.js +5 -3
  2. package/dist/auth/auth.d.ts +4 -6
  3. package/dist/auth/auth.js +5 -9
  4. package/dist/auth/drivers/ldap.d.ts +3 -3
  5. package/dist/auth/drivers/ldap.js +11 -4
  6. package/dist/auth/drivers/local.d.ts +2 -2
  7. package/dist/auth/drivers/local.js +5 -12
  8. package/dist/auth/drivers/oauth2.d.ts +4 -4
  9. package/dist/auth/drivers/oauth2.js +47 -21
  10. package/dist/auth/drivers/openid.d.ts +4 -4
  11. package/dist/auth/drivers/openid.js +35 -19
  12. package/dist/cli/commands/bootstrap/index.js +3 -2
  13. package/dist/cli/commands/init/index.js +3 -7
  14. package/dist/cli/commands/schema/apply.js +1 -1
  15. package/dist/cli/utils/defaults.d.ts +11 -0
  16. package/dist/cli/utils/defaults.js +14 -0
  17. package/dist/constants.d.ts +8 -0
  18. package/dist/constants.js +16 -2
  19. package/dist/controllers/shares.d.ts +2 -0
  20. package/dist/controllers/shares.js +212 -0
  21. package/dist/controllers/users.js +21 -9
  22. package/dist/database/migrations/20211211A-add-shares.d.ts +3 -0
  23. package/dist/database/migrations/20211211A-add-shares.js +37 -0
  24. package/dist/database/run-ast.js +5 -5
  25. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -15
  26. package/dist/database/system-data/app-access-permissions/index.d.ts +1 -0
  27. package/dist/database/system-data/app-access-permissions/index.js +4 -2
  28. package/dist/database/system-data/app-access-permissions/schema-access-permissions.yaml +17 -0
  29. package/dist/database/system-data/collections/collections.yaml +3 -0
  30. package/dist/database/system-data/fields/sessions.yaml +1 -1
  31. package/dist/database/system-data/fields/shares.yaml +73 -0
  32. package/dist/database/system-data/fields/users.yaml +1 -1
  33. package/dist/database/system-data/relations/relations.yaml +15 -0
  34. package/dist/emitter.d.ts +3 -2
  35. package/dist/emitter.js +13 -6
  36. package/dist/exceptions/index.d.ts +2 -0
  37. package/dist/exceptions/index.js +2 -0
  38. package/dist/exceptions/invalid-token.d.ts +4 -0
  39. package/dist/exceptions/invalid-token.js +10 -0
  40. package/dist/exceptions/unexpected-response.d.ts +4 -0
  41. package/dist/exceptions/unexpected-response.js +10 -0
  42. package/dist/extensions.d.ts +1 -0
  43. package/dist/extensions.js +10 -4
  44. package/dist/middleware/authenticate.js +5 -15
  45. package/dist/middleware/check-ip.js +9 -6
  46. package/dist/middleware/respond.js +4 -1
  47. package/dist/services/activity.d.ts +2 -1
  48. package/dist/services/activity.js +2 -2
  49. package/dist/services/authentication.d.ts +2 -7
  50. package/dist/services/authentication.js +81 -41
  51. package/dist/services/authorization.js +3 -3
  52. package/dist/services/collections.d.ts +1 -2
  53. package/dist/services/collections.js +2 -2
  54. package/dist/services/files.d.ts +2 -2
  55. package/dist/services/files.js +14 -8
  56. package/dist/services/graphql.js +16 -5
  57. package/dist/services/index.d.ts +1 -0
  58. package/dist/services/index.js +1 -0
  59. package/dist/services/items.d.ts +1 -15
  60. package/dist/services/notifications.d.ts +2 -2
  61. package/dist/services/permissions.d.ts +2 -2
  62. package/dist/services/roles.d.ts +2 -2
  63. package/dist/services/shares.d.ts +17 -0
  64. package/dist/services/shares.js +135 -0
  65. package/dist/services/specifications.js +1 -1
  66. package/dist/services/users.d.ts +2 -2
  67. package/dist/services/users.js +8 -6
  68. package/dist/services/webhooks.d.ts +2 -2
  69. package/dist/tests/database/migrations/run.test.d.ts +1 -0
  70. package/dist/tests/database/migrations/run.test.js +29 -0
  71. package/dist/types/ast.d.ts +3 -3
  72. package/dist/types/auth.d.ts +31 -0
  73. package/dist/types/extensions.d.ts +2 -0
  74. package/dist/types/items.d.ts +14 -0
  75. package/dist/utils/apply-query.d.ts +0 -38
  76. package/dist/utils/apply-query.js +67 -69
  77. package/dist/utils/apply-snapshot.js +69 -14
  78. package/dist/utils/get-ast-from-query.js +3 -3
  79. package/dist/utils/get-permissions.d.ts +2 -2
  80. package/dist/utils/get-permissions.js +117 -72
  81. package/dist/utils/get-relation-type.d.ts +1 -1
  82. package/dist/utils/get-relation-type.js +1 -1
  83. package/dist/utils/merge-permissions-for-share.d.ts +5 -0
  84. package/dist/utils/merge-permissions-for-share.js +116 -0
  85. package/dist/utils/merge-permissions.d.ts +13 -1
  86. package/dist/utils/merge-permissions.js +29 -21
  87. package/dist/utils/reduce-schema.d.ts +2 -2
  88. package/dist/utils/reduce-schema.js +7 -7
  89. package/dist/utils/user-name.js +3 -0
  90. package/package.json +14 -13
@@ -15,6 +15,7 @@ const create_env_1 = __importDefault(require("../../utils/create-env"));
15
15
  const drivers_1 = require("../../utils/drivers");
16
16
  const questions_1 = require("./questions");
17
17
  const generate_hash_1 = require("../../../utils/generate-hash");
18
+ const defaults_1 = require("../../utils/defaults");
18
19
  async function init() {
19
20
  const rootPath = process.cwd();
20
21
  const { client } = await inquirer_1.default.prompt([
@@ -79,19 +80,14 @@ async function init() {
79
80
  const roleID = (0, uuid_1.v4)();
80
81
  await db('directus_roles').insert({
81
82
  id: roleID,
82
- name: 'Administrator',
83
- icon: 'verified',
84
- admin_access: true,
85
- description: 'Initial administrative role with unrestricted App/API access',
83
+ ...defaults_1.defaultAdminRole,
86
84
  });
87
85
  await db('directus_users').insert({
88
86
  id: userID,
89
- status: 'active',
90
87
  email: firstUser.email,
91
88
  password: firstUser.password,
92
- first_name: 'Admin',
93
- last_name: 'User',
94
89
  role: roleID,
90
+ ...defaults_1.defaultAdminUser,
95
91
  });
96
92
  await db.destroy();
97
93
  process.stdout.write(`\nYour project has been created at ${chalk_1.default.green(rootPath)}.\n`);
@@ -135,7 +135,7 @@ async function apply(snapshotPath, options) {
135
135
  else {
136
136
  continue;
137
137
  }
138
- // Related collection doesn't exist for m2a relationship types
138
+ // Related collection doesn't exist for a2o relationship types
139
139
  if (related_collection) {
140
140
  message += `-> ${related_collection}`;
141
141
  }
@@ -0,0 +1,11 @@
1
+ export declare const defaultAdminRole: {
2
+ name: string;
3
+ icon: string;
4
+ admin_access: boolean;
5
+ description: string;
6
+ };
7
+ export declare const defaultAdminUser: {
8
+ status: string;
9
+ first_name: string;
10
+ last_name: string;
11
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultAdminUser = exports.defaultAdminRole = void 0;
4
+ exports.defaultAdminRole = {
5
+ name: 'Administrator',
6
+ icon: 'verified',
7
+ admin_access: true,
8
+ description: '$t:admin_description',
9
+ };
10
+ exports.defaultAdminUser = {
11
+ status: 'active',
12
+ first_name: 'Admin',
13
+ last_name: 'User',
14
+ };
@@ -5,3 +5,11 @@ export declare const FILTER_VARIABLES: string[];
5
5
  export declare const ALIAS_TYPES: string[];
6
6
  export declare const DEFAULT_AUTH_PROVIDER = "default";
7
7
  export declare const COLUMN_TRANSFORMS: string[];
8
+ export declare const UUID_REGEX = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
9
+ export declare const COOKIE_OPTIONS: {
10
+ httpOnly: boolean;
11
+ domain: any;
12
+ maxAge: number;
13
+ secure: any;
14
+ sameSite: "lax" | "strict" | "none";
15
+ };
package/dist/constants.js CHANGED
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ var _a;
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.COLUMN_TRANSFORMS = exports.DEFAULT_AUTH_PROVIDER = exports.ALIAS_TYPES = exports.FILTER_VARIABLES = exports.ASSET_TRANSFORM_QUERY_KEYS = exports.SYSTEM_ASSET_ALLOW_LIST = void 0;
7
+ exports.COOKIE_OPTIONS = exports.UUID_REGEX = exports.COLUMN_TRANSFORMS = exports.DEFAULT_AUTH_PROVIDER = exports.ALIAS_TYPES = exports.FILTER_VARIABLES = exports.ASSET_TRANSFORM_QUERY_KEYS = exports.SYSTEM_ASSET_ALLOW_LIST = void 0;
8
+ const env_1 = __importDefault(require("./env"));
9
+ const ms_1 = __importDefault(require("ms"));
4
10
  exports.SYSTEM_ASSET_ALLOW_LIST = [
5
11
  {
6
12
  key: 'system-small-cover',
@@ -38,6 +44,14 @@ exports.ASSET_TRANSFORM_QUERY_KEYS = [
38
44
  'withoutEnlargement',
39
45
  ];
40
46
  exports.FILTER_VARIABLES = ['$NOW', '$CURRENT_USER', '$CURRENT_ROLE'];
41
- exports.ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'm2a', 'files', 'translations'];
47
+ exports.ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'm2a', 'o2a', 'files', 'translations'];
42
48
  exports.DEFAULT_AUTH_PROVIDER = 'default';
43
49
  exports.COLUMN_TRANSFORMS = ['year', 'month', 'day', 'weekday', 'hour', 'minute', 'second'];
50
+ exports.UUID_REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
51
+ exports.COOKIE_OPTIONS = {
52
+ httpOnly: true,
53
+ domain: env_1.default.REFRESH_TOKEN_COOKIE_DOMAIN,
54
+ maxAge: (0, ms_1.default)(env_1.default.REFRESH_TOKEN_TTL),
55
+ secure: (_a = env_1.default.REFRESH_TOKEN_COOKIE_SECURE) !== null && _a !== void 0 ? _a : false,
56
+ sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
57
+ };
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,212 @@
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 express_1 = __importDefault(require("express"));
7
+ const exceptions_1 = require("../exceptions");
8
+ const respond_1 = require("../middleware/respond");
9
+ const use_collection_1 = __importDefault(require("../middleware/use-collection"));
10
+ const validate_batch_1 = require("../middleware/validate-batch");
11
+ const services_1 = require("../services");
12
+ const async_handler_1 = __importDefault(require("../utils/async-handler"));
13
+ const constants_1 = require("../constants");
14
+ const joi_1 = __importDefault(require("joi"));
15
+ const env_1 = __importDefault(require("../env"));
16
+ const router = express_1.default.Router();
17
+ router.use((0, use_collection_1.default)('directus_shares'));
18
+ const sharedLoginSchema = joi_1.default.object({
19
+ share: joi_1.default.string().required(),
20
+ password: joi_1.default.string(),
21
+ }).unknown();
22
+ router.post('/auth', (0, async_handler_1.default)(async (req, res, next) => {
23
+ // This doesn't use accountability, as the user isn't logged in at this point
24
+ const service = new services_1.SharesService({
25
+ schema: req.schema,
26
+ });
27
+ const { error } = sharedLoginSchema.validate(req.body);
28
+ if (error) {
29
+ throw new exceptions_1.InvalidPayloadException(error.message);
30
+ }
31
+ const { accessToken, refreshToken, expires } = await service.login(req.body);
32
+ res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, constants_1.COOKIE_OPTIONS);
33
+ res.locals.payload = { data: { access_token: accessToken, expires } };
34
+ return next();
35
+ }), respond_1.respond);
36
+ const sharedInviteSchema = joi_1.default.object({
37
+ share: joi_1.default.string().required(),
38
+ emails: joi_1.default.array().items(joi_1.default.string()),
39
+ }).unknown();
40
+ router.post('/invite', (0, async_handler_1.default)(async (req, res, next) => {
41
+ const service = new services_1.SharesService({
42
+ schema: req.schema,
43
+ accountability: req.accountability,
44
+ });
45
+ const { error } = sharedInviteSchema.validate(req.body);
46
+ if (error) {
47
+ throw new exceptions_1.InvalidPayloadException(error.message);
48
+ }
49
+ await service.invite(req.body);
50
+ return next();
51
+ }), respond_1.respond);
52
+ router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
53
+ const service = new services_1.SharesService({
54
+ accountability: req.accountability,
55
+ schema: req.schema,
56
+ });
57
+ const savedKeys = [];
58
+ if (Array.isArray(req.body)) {
59
+ const keys = await service.createMany(req.body);
60
+ savedKeys.push(...keys);
61
+ }
62
+ else {
63
+ const key = await service.createOne(req.body);
64
+ savedKeys.push(key);
65
+ }
66
+ try {
67
+ if (Array.isArray(req.body)) {
68
+ const items = await service.readMany(savedKeys, req.sanitizedQuery);
69
+ res.locals.payload = { data: items };
70
+ }
71
+ else {
72
+ const item = await service.readOne(savedKeys[0], req.sanitizedQuery);
73
+ res.locals.payload = { data: item };
74
+ }
75
+ }
76
+ catch (error) {
77
+ if (error instanceof exceptions_1.ForbiddenException) {
78
+ return next();
79
+ }
80
+ throw error;
81
+ }
82
+ return next();
83
+ }), respond_1.respond);
84
+ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
85
+ const service = new services_1.SharesService({
86
+ accountability: req.accountability,
87
+ schema: req.schema,
88
+ });
89
+ const records = await service.readByQuery(req.sanitizedQuery);
90
+ res.locals.payload = { data: records || null };
91
+ return next();
92
+ });
93
+ router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
94
+ router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
95
+ router.get(`/info/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, res, next) => {
96
+ const service = new services_1.SharesService({
97
+ schema: req.schema,
98
+ });
99
+ const record = await service.readOne(req.params.pk, {
100
+ fields: ['id', 'collection', 'item', 'password', 'max_uses', 'times_used', 'date_start', 'date_end'],
101
+ filter: {
102
+ _and: [
103
+ {
104
+ _or: [
105
+ {
106
+ date_start: {
107
+ _lte: '$NOW',
108
+ },
109
+ },
110
+ {
111
+ date_start: {
112
+ _null: true,
113
+ },
114
+ },
115
+ ],
116
+ },
117
+ {
118
+ _or: [
119
+ {
120
+ date_end: {
121
+ _gte: '$NOW',
122
+ },
123
+ },
124
+ {
125
+ date_end: {
126
+ _null: true,
127
+ },
128
+ },
129
+ ],
130
+ },
131
+ ],
132
+ },
133
+ });
134
+ res.locals.payload = { data: record || null };
135
+ return next();
136
+ }), respond_1.respond);
137
+ router.get(`/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, res, next) => {
138
+ const service = new services_1.SharesService({
139
+ accountability: req.accountability,
140
+ schema: req.schema,
141
+ });
142
+ const record = await service.readOne(req.params.pk, req.sanitizedQuery);
143
+ res.locals.payload = { data: record || null };
144
+ return next();
145
+ }), respond_1.respond);
146
+ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handler_1.default)(async (req, res, next) => {
147
+ const service = new services_1.SharesService({
148
+ accountability: req.accountability,
149
+ schema: req.schema,
150
+ });
151
+ let keys = [];
152
+ if (req.body.keys) {
153
+ keys = await service.updateMany(req.body.keys, req.body.data);
154
+ }
155
+ else {
156
+ keys = await service.updateByQuery(req.body.query, req.body.data);
157
+ }
158
+ try {
159
+ const result = await service.readMany(keys, req.sanitizedQuery);
160
+ res.locals.payload = { data: result };
161
+ }
162
+ catch (error) {
163
+ if (error instanceof exceptions_1.ForbiddenException) {
164
+ return next();
165
+ }
166
+ throw error;
167
+ }
168
+ return next();
169
+ }), respond_1.respond);
170
+ router.patch(`/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, res, next) => {
171
+ const service = new services_1.SharesService({
172
+ accountability: req.accountability,
173
+ schema: req.schema,
174
+ });
175
+ const primaryKey = await service.updateOne(req.params.pk, req.body);
176
+ try {
177
+ const item = await service.readOne(primaryKey, req.sanitizedQuery);
178
+ res.locals.payload = { data: item || null };
179
+ }
180
+ catch (error) {
181
+ if (error instanceof exceptions_1.ForbiddenException) {
182
+ return next();
183
+ }
184
+ throw error;
185
+ }
186
+ return next();
187
+ }), respond_1.respond);
188
+ router.delete('/', (0, async_handler_1.default)(async (req, _res, next) => {
189
+ const service = new services_1.SharesService({
190
+ accountability: req.accountability,
191
+ schema: req.schema,
192
+ });
193
+ if (Array.isArray(req.body)) {
194
+ await service.deleteMany(req.body);
195
+ }
196
+ else if (req.body.keys) {
197
+ await service.deleteMany(req.body.keys);
198
+ }
199
+ else {
200
+ await service.deleteByQuery(req.body.query);
201
+ }
202
+ return next();
203
+ }), respond_1.respond);
204
+ router.delete(`/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, _res, next) => {
205
+ const service = new services_1.SharesService({
206
+ accountability: req.accountability,
207
+ schema: req.schema,
208
+ });
209
+ await service.deleteOne(req.params.pk);
210
+ return next();
211
+ }), respond_1.respond);
212
+ exports.default = router;
@@ -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 (!((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user)) {
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, res, next) => {
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, res, next) => {
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, res, next) => {
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, res, next) => {
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, res, next) => {
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, res, next) => {
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, res, next) => {
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,3 @@
1
+ import { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,37 @@
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
+ table.timestamp('date_start');
15
+ table.timestamp('date_end');
16
+ table.integer('times_used').defaultTo(0);
17
+ table.integer('max_uses');
18
+ });
19
+ await knex.schema.alterTable('directus_sessions', (table) => {
20
+ table.dropColumn('data');
21
+ });
22
+ await knex.schema.alterTable('directus_sessions', (table) => {
23
+ table.uuid('user').nullable().alter();
24
+ table.uuid('share').references('id').inTable('directus_shares').onDelete('CASCADE');
25
+ });
26
+ }
27
+ exports.up = up;
28
+ async function down(knex) {
29
+ await knex.schema.alterTable('directus_sessions', (table) => {
30
+ table.uuid('user').notNullable().alter();
31
+ table.json('data');
32
+ table.dropForeign('share');
33
+ table.dropColumn('share');
34
+ });
35
+ await knex.schema.dropTable('directus_shares');
36
+ }
37
+ exports.down = down;
@@ -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 === 'm2a') {
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 === 'm2a') {
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 === 'm2a') {
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 === 'm2a') {
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 === 'm2a') {
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,2 +1,3 @@
1
1
  import { Permission } from '@directus/shared/types';
2
+ export declare const schemaPermissions: Permission[];
2
3
  export declare const appAccessMinimalPermissions: Permission[];
@@ -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.appAccessMinimalPermissions = permissions.map((row) => (0, lodash_1.merge)({}, defaults, row));
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
@@ -65,3 +65,6 @@ data:
65
65
  note: $t:directus_collection.directus_panels
66
66
  - collection: directus_notifications
67
67
  note: $t:directus_collection.directus_notifications
68
+ - collection: directus_shares
69
+ icon: share
70
+ note: $t:directus_collection.directus_shares
@@ -11,4 +11,4 @@ fields:
11
11
  width: half
12
12
  - field: user_agent
13
13
  width: half
14
- - field: data
14
+ - field: share
@@ -0,0 +1,73 @@
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
+
36
+ - field: date_start
37
+ width: half
38
+
39
+ - field: date_end
40
+ width: half
41
+
42
+ - field: max_uses
43
+ width: half
44
+
45
+ - field: times_used
46
+ width: half
47
+ readonly: true
48
+
49
+ - field: date_created
50
+ special: date-created
51
+ width: half
52
+ readonly: true
53
+ conditions:
54
+ - name: notCreatedYet
55
+ rule:
56
+ id:
57
+ _null: true
58
+ hidden: true
59
+
60
+ - field: user_created
61
+ special: user-created
62
+ interface: select-dropdown-m2o
63
+ width: half
64
+ display: user
65
+ options:
66
+ template: '{{avatar.$thumbnail}} {{first_name}} {{last_name}}'
67
+ readonly: true
68
+ conditions:
69
+ - name: notCreatedYet
70
+ rule:
71
+ id:
72
+ _null: true
73
+ hidden: true
@@ -100,7 +100,7 @@ fields:
100
100
  options:
101
101
  icon: verified_user
102
102
  title: $t:fields.directus_users.admin_options
103
- color: '#E35169'
103
+ color: 'var(--danger)'
104
104
  special:
105
105
  - alias
106
106
  - no-data