directus 9.2.2 → 9.4.2

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 (96) hide show
  1. package/dist/app.js +16 -4
  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 +2 -3
  6. package/dist/auth/drivers/local.d.ts +2 -2
  7. package/dist/auth/drivers/local.js +7 -13
  8. package/dist/auth/drivers/oauth2.d.ts +3 -3
  9. package/dist/auth/drivers/oauth2.js +4 -4
  10. package/dist/auth/drivers/openid.d.ts +3 -3
  11. package/dist/auth/drivers/openid.js +4 -4
  12. package/dist/cache.js +1 -3
  13. package/dist/cli/commands/bootstrap/index.js +3 -2
  14. package/dist/cli/commands/init/index.js +3 -7
  15. package/dist/cli/commands/schema/apply.js +1 -1
  16. package/dist/cli/utils/defaults.d.ts +11 -0
  17. package/dist/cli/utils/defaults.js +14 -0
  18. package/dist/constants.d.ts +8 -0
  19. package/dist/constants.js +16 -2
  20. package/dist/controllers/activity.js +2 -1
  21. package/dist/controllers/auth.js +5 -4
  22. package/dist/controllers/shares.d.ts +2 -0
  23. package/dist/controllers/shares.js +212 -0
  24. package/dist/controllers/users.js +21 -9
  25. package/dist/database/index.js +3 -0
  26. package/dist/database/migrations/20211211A-add-shares.d.ts +3 -0
  27. package/dist/database/migrations/20211211A-add-shares.js +38 -0
  28. package/dist/database/migrations/20211230A-add-project-descriptor.d.ts +3 -0
  29. package/dist/database/migrations/20211230A-add-project-descriptor.js +15 -0
  30. package/dist/database/run-ast.js +5 -5
  31. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -15
  32. package/dist/database/system-data/app-access-permissions/index.d.ts +1 -0
  33. package/dist/database/system-data/app-access-permissions/index.js +4 -2
  34. package/dist/database/system-data/app-access-permissions/schema-access-permissions.yaml +17 -0
  35. package/dist/database/system-data/collections/collections.yaml +3 -0
  36. package/dist/database/system-data/fields/_defaults.yaml +2 -0
  37. package/dist/database/system-data/fields/sessions.yaml +1 -1
  38. package/dist/database/system-data/fields/settings.yaml +20 -1
  39. package/dist/database/system-data/fields/shares.yaml +77 -0
  40. package/dist/database/system-data/fields/users.yaml +1 -1
  41. package/dist/database/system-data/relations/relations.yaml +15 -0
  42. package/dist/emitter.d.ts +3 -2
  43. package/dist/emitter.js +13 -6
  44. package/dist/env.js +3 -1
  45. package/dist/extensions.d.ts +1 -0
  46. package/dist/extensions.js +10 -4
  47. package/dist/middleware/authenticate.js +7 -16
  48. package/dist/middleware/check-ip.js +9 -6
  49. package/dist/middleware/rate-limiter.js +2 -1
  50. package/dist/middleware/respond.js +4 -1
  51. package/dist/services/activity.d.ts +2 -1
  52. package/dist/services/activity.js +2 -2
  53. package/dist/services/authentication.d.ts +2 -7
  54. package/dist/services/authentication.js +81 -41
  55. package/dist/services/authorization.js +3 -3
  56. package/dist/services/collections.d.ts +1 -2
  57. package/dist/services/collections.js +2 -2
  58. package/dist/services/files.d.ts +2 -2
  59. package/dist/services/files.js +14 -8
  60. package/dist/services/graphql.d.ts +1 -1
  61. package/dist/services/graphql.js +47 -6
  62. package/dist/services/index.d.ts +1 -0
  63. package/dist/services/index.js +1 -0
  64. package/dist/services/items.d.ts +1 -15
  65. package/dist/services/notifications.d.ts +2 -2
  66. package/dist/services/permissions.d.ts +2 -2
  67. package/dist/services/roles.d.ts +2 -2
  68. package/dist/services/server.js +1 -0
  69. package/dist/services/shares.d.ts +17 -0
  70. package/dist/services/shares.js +135 -0
  71. package/dist/services/specifications.js +1 -1
  72. package/dist/services/users.d.ts +2 -2
  73. package/dist/services/webhooks.d.ts +2 -2
  74. package/dist/types/ast.d.ts +3 -3
  75. package/dist/types/auth.d.ts +31 -0
  76. package/dist/types/extensions.d.ts +2 -0
  77. package/dist/types/items.d.ts +14 -0
  78. package/dist/utils/apply-query.d.ts +0 -38
  79. package/dist/utils/apply-query.js +66 -67
  80. package/dist/utils/apply-snapshot.js +69 -14
  81. package/dist/utils/get-ast-from-query.js +3 -3
  82. package/dist/utils/get-default-value.js +3 -1
  83. package/dist/utils/get-ip-from-req.d.ts +2 -0
  84. package/dist/utils/get-ip-from-req.js +24 -0
  85. package/dist/utils/get-permissions.js +15 -7
  86. package/dist/utils/get-relation-type.d.ts +1 -1
  87. package/dist/utils/get-relation-type.js +1 -1
  88. package/dist/utils/merge-permissions-for-share.d.ts +5 -0
  89. package/dist/utils/merge-permissions-for-share.js +116 -0
  90. package/dist/utils/merge-permissions.d.ts +13 -1
  91. package/dist/utils/merge-permissions.js +27 -19
  92. package/dist/utils/reduce-schema.d.ts +2 -2
  93. package/dist/utils/reduce-schema.js +7 -7
  94. package/dist/utils/user-name.js +3 -0
  95. package/example.env +1 -1
  96. package/package.json +15 -14
@@ -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: new Date().toISOString(),
108
+ },
109
+ },
110
+ {
111
+ date_start: {
112
+ _null: true,
113
+ },
114
+ },
115
+ ],
116
+ },
117
+ {
118
+ _or: [
119
+ {
120
+ date_end: {
121
+ _gte: new Date().toISOString(),
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();
@@ -88,6 +88,9 @@ function getDatabase() {
88
88
  // act the same
89
89
  (0, lodash_1.merge)(knexConfig, { connection: { options: { useUTC: false } } });
90
90
  }
91
+ if (env_1.default.DB_CLIENT === 'mysql' && !env_1.default.DB_CHARSET) {
92
+ logger_1.default.warn(`DB_CHARSET hasn't been set. Please make sure DB_CHARSET matches your database's collation.`);
93
+ }
91
94
  database = (0, knex_1.knex)(knexConfig);
92
95
  const times = {};
93
96
  database
@@ -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,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;
@@ -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,15 @@
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.alterTable('directus_settings', (table) => {
6
+ table.string('project_descriptor', 100).nullable();
7
+ });
8
+ }
9
+ exports.up = up;
10
+ async function down(knex) {
11
+ await knex.schema.alterTable('directus_settings', (table) => {
12
+ table.dropColumn('project_descriptor');
13
+ });
14
+ }
15
+ 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
@@ -12,3 +12,5 @@ width: full
12
12
  group: null
13
13
  translations: null
14
14
  note: null
15
+ conditions: null
16
+ required: false
@@ -11,4 +11,4 @@ fields:
11
11
  width: half
12
12
  - field: user_agent
13
13
  width: half
14
- - field: data
14
+ - field: share
@@ -14,6 +14,16 @@ fields:
14
14
  translations: Name
15
15
  width: half
16
16
 
17
+ - field: project_descriptor
18
+ interface: input
19
+ options:
20
+ iconRight: title
21
+ placeholder: $t:field_options.directus_settings.project_name_placeholder
22
+ translations:
23
+ language: en-US
24
+ translations: Name
25
+ width: half
26
+
17
27
  - field: project_url
18
28
  interface: input
19
29
  options:
@@ -22,7 +32,7 @@ fields:
22
32
  translations:
23
33
  language: en-US
24
34
  translations: Website
25
- width: half
35
+ width: full
26
36
 
27
37
  - field: branding_divider
28
38
  interface: presentation-divider
@@ -343,3 +353,12 @@ fields:
343
353
  type:
344
354
  _neq: 'raster'
345
355
  hidden: true
356
+ - field: attribution
357
+ name: $t:fields.directus_settings.attribution
358
+ type: string
359
+ schema:
360
+ is_nullable: true
361
+ meta:
362
+ interface: input
363
+ options:
364
+ 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
@@ -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
@@ -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