@directus/api 24.0.1 → 25.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +10 -4
- package/dist/auth/drivers/oauth2.js +2 -3
- package/dist/auth/drivers/openid.js +2 -3
- package/dist/cache.d.ts +2 -2
- package/dist/cache.js +20 -7
- package/dist/controllers/assets.js +2 -2
- package/dist/controllers/metrics.d.ts +2 -0
- package/dist/controllers/metrics.js +33 -0
- package/dist/controllers/server.js +1 -1
- package/dist/database/helpers/number/dialects/mssql.d.ts +2 -2
- package/dist/database/helpers/number/dialects/mssql.js +3 -3
- package/dist/database/helpers/number/dialects/oracle.d.ts +2 -2
- package/dist/database/helpers/number/dialects/oracle.js +2 -2
- package/dist/database/helpers/number/dialects/sqlite.d.ts +2 -2
- package/dist/database/helpers/number/dialects/sqlite.js +2 -2
- package/dist/database/helpers/number/types.d.ts +2 -2
- package/dist/database/helpers/number/types.js +2 -2
- package/dist/database/index.js +3 -0
- package/dist/metrics/index.d.ts +1 -0
- package/dist/metrics/index.js +1 -0
- package/dist/metrics/lib/create-metrics.d.ts +15 -0
- package/dist/metrics/lib/create-metrics.js +239 -0
- package/dist/metrics/lib/use-metrics.d.ts +17 -0
- package/dist/metrics/lib/use-metrics.js +15 -0
- package/dist/metrics/types/metric.d.ts +1 -0
- package/dist/metrics/types/metric.js +1 -0
- package/dist/middleware/respond.js +7 -1
- package/dist/operations/condition/index.js +7 -2
- package/dist/schedules/metrics.d.ts +7 -0
- package/dist/schedules/metrics.js +44 -0
- package/dist/services/assets.d.ts +6 -1
- package/dist/services/assets.js +8 -6
- package/dist/services/fields.js +1 -1
- package/dist/services/graphql/errors/format.d.ts +6 -0
- package/dist/services/graphql/errors/format.js +14 -0
- package/dist/services/graphql/index.d.ts +5 -53
- package/dist/services/graphql/index.js +5 -2720
- package/dist/services/graphql/resolvers/mutation.d.ts +4 -0
- package/dist/services/graphql/resolvers/mutation.js +74 -0
- package/dist/services/graphql/resolvers/query.d.ts +8 -0
- package/dist/services/graphql/resolvers/query.js +87 -0
- package/dist/services/graphql/resolvers/system-admin.d.ts +5 -0
- package/dist/services/graphql/resolvers/system-admin.js +236 -0
- package/dist/services/graphql/resolvers/system-global.d.ts +7 -0
- package/dist/services/graphql/resolvers/system-global.js +435 -0
- package/dist/services/graphql/resolvers/system.d.ts +11 -0
- package/dist/services/graphql/resolvers/system.js +554 -0
- package/dist/services/graphql/schema/get-types.d.ts +12 -0
- package/dist/services/graphql/schema/get-types.js +223 -0
- package/dist/services/graphql/schema/index.d.ts +32 -0
- package/dist/services/graphql/schema/index.js +190 -0
- package/dist/services/graphql/schema/parse-args.d.ts +9 -0
- package/dist/services/graphql/schema/parse-args.js +35 -0
- package/dist/services/graphql/schema/parse-query.d.ts +7 -0
- package/dist/services/graphql/schema/parse-query.js +98 -0
- package/dist/services/graphql/schema/read.d.ts +12 -0
- package/dist/services/graphql/schema/read.js +653 -0
- package/dist/services/graphql/schema/write.d.ts +9 -0
- package/dist/services/graphql/schema/write.js +142 -0
- package/dist/services/graphql/subscription.d.ts +1 -1
- package/dist/services/graphql/subscription.js +7 -6
- package/dist/services/graphql/utils/aggrgate-query.d.ts +6 -0
- package/dist/services/graphql/utils/aggrgate-query.js +32 -0
- package/dist/services/graphql/utils/replace-fragments.d.ts +6 -0
- package/dist/services/graphql/utils/replace-fragments.js +21 -0
- package/dist/services/graphql/utils/replace-funcs.d.ts +5 -0
- package/dist/services/graphql/utils/replace-funcs.js +21 -0
- package/dist/services/graphql/utils/sanitize-gql-schema.d.ts +1 -1
- package/dist/services/graphql/utils/sanitize-gql-schema.js +5 -5
- package/dist/services/items.js +0 -2
- package/dist/services/meta.js +25 -84
- package/dist/services/users.d.ts +4 -0
- package/dist/services/users.js +23 -1
- package/dist/utils/apply-query.d.ts +1 -1
- package/dist/utils/apply-query.js +58 -21
- package/dist/utils/freeze-schema.d.ts +3 -0
- package/dist/utils/freeze-schema.js +31 -0
- package/dist/utils/get-accountability-for-token.js +1 -0
- package/dist/utils/get-milliseconds.js +1 -1
- package/dist/utils/get-schema.js +10 -5
- package/dist/utils/permissions-cachable.d.ts +8 -0
- package/dist/utils/permissions-cachable.js +38 -0
- package/dist/utils/sanitize-schema.d.ts +1 -1
- package/dist/websocket/messages.d.ts +6 -6
- package/package.json +22 -19
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { toBoolean } from '@directus/utils';
|
|
3
|
+
import { GraphQLBoolean, GraphQLEnumType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLString, } from 'graphql';
|
|
4
|
+
import { GraphQLJSON, ObjectTypeComposer, SchemaComposer, toInputObjectType } from 'graphql-compose';
|
|
5
|
+
import getDatabase from '../../../database/index.js';
|
|
6
|
+
import { fetchAccountabilityCollectionAccess } from '../../../permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js';
|
|
7
|
+
import { fetchAccountabilityPolicyGlobals } from '../../../permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js';
|
|
8
|
+
import { getGraphQLType } from '../../../utils/get-graphql-type.js';
|
|
9
|
+
import { CollectionsService } from '../../collections.js';
|
|
10
|
+
import { FieldsService } from '../../fields.js';
|
|
11
|
+
import { FilesService } from '../../files.js';
|
|
12
|
+
import { RelationsService } from '../../relations.js';
|
|
13
|
+
import { RolesService } from '../../roles.js';
|
|
14
|
+
import { ServerService } from '../../server.js';
|
|
15
|
+
import { SpecificationService } from '../../specifications.js';
|
|
16
|
+
import { UsersService } from '../../users.js';
|
|
17
|
+
import { GraphQLService } from '../index.js';
|
|
18
|
+
import { generateSchema } from '../schema/index.js';
|
|
19
|
+
import { getQuery } from '../schema/parse-query.js';
|
|
20
|
+
import { replaceFragmentsInSelections } from '../utils/replace-fragments.js';
|
|
21
|
+
import { resolveSystemAdmin } from './system-admin.js';
|
|
22
|
+
import { globalResolvers } from './system-global.js';
|
|
23
|
+
const env = useEnv();
|
|
24
|
+
export function injectSystemResolvers(gql, schemaComposer, { CreateCollectionTypes, ReadCollectionTypes, UpdateCollectionTypes }, schema) {
|
|
25
|
+
globalResolvers(gql, schemaComposer);
|
|
26
|
+
const ServerInfo = schemaComposer.createObjectTC({
|
|
27
|
+
name: 'server_info',
|
|
28
|
+
fields: {
|
|
29
|
+
project: {
|
|
30
|
+
type: new GraphQLObjectType({
|
|
31
|
+
name: 'server_info_project',
|
|
32
|
+
fields: {
|
|
33
|
+
project_name: { type: GraphQLString },
|
|
34
|
+
project_descriptor: { type: GraphQLString },
|
|
35
|
+
project_logo: { type: GraphQLString },
|
|
36
|
+
project_color: { type: GraphQLString },
|
|
37
|
+
default_language: { type: GraphQLString },
|
|
38
|
+
public_foreground: { type: GraphQLString },
|
|
39
|
+
public_background: { type: GraphQLString },
|
|
40
|
+
public_note: { type: GraphQLString },
|
|
41
|
+
custom_css: { type: GraphQLString },
|
|
42
|
+
public_registration: { type: GraphQLBoolean },
|
|
43
|
+
public_registration_verify_email: { type: GraphQLBoolean },
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
if (gql.accountability?.user) {
|
|
50
|
+
ServerInfo.addFields({
|
|
51
|
+
rateLimit: env['RATE_LIMITER_ENABLED']
|
|
52
|
+
? {
|
|
53
|
+
type: new GraphQLObjectType({
|
|
54
|
+
name: 'server_info_rate_limit',
|
|
55
|
+
fields: {
|
|
56
|
+
points: { type: GraphQLInt },
|
|
57
|
+
duration: { type: GraphQLInt },
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
}
|
|
61
|
+
: GraphQLBoolean,
|
|
62
|
+
rateLimitGlobal: env['RATE_LIMITER_GLOBAL_ENABLED']
|
|
63
|
+
? {
|
|
64
|
+
type: new GraphQLObjectType({
|
|
65
|
+
name: 'server_info_rate_limit_global',
|
|
66
|
+
fields: {
|
|
67
|
+
points: { type: GraphQLInt },
|
|
68
|
+
duration: { type: GraphQLInt },
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
}
|
|
72
|
+
: GraphQLBoolean,
|
|
73
|
+
websocket: toBoolean(env['WEBSOCKETS_ENABLED'])
|
|
74
|
+
? {
|
|
75
|
+
type: new GraphQLObjectType({
|
|
76
|
+
name: 'server_info_websocket',
|
|
77
|
+
fields: {
|
|
78
|
+
rest: {
|
|
79
|
+
type: toBoolean(env['WEBSOCKETS_REST_ENABLED'])
|
|
80
|
+
? new GraphQLObjectType({
|
|
81
|
+
name: 'server_info_websocket_rest',
|
|
82
|
+
fields: {
|
|
83
|
+
authentication: {
|
|
84
|
+
type: new GraphQLEnumType({
|
|
85
|
+
name: 'server_info_websocket_rest_authentication',
|
|
86
|
+
values: {
|
|
87
|
+
public: { value: 'public' },
|
|
88
|
+
handshake: { value: 'handshake' },
|
|
89
|
+
strict: { value: 'strict' },
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
},
|
|
93
|
+
path: { type: GraphQLString },
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
: GraphQLBoolean,
|
|
97
|
+
},
|
|
98
|
+
graphql: {
|
|
99
|
+
type: toBoolean(env['WEBSOCKETS_GRAPHQL_ENABLED'])
|
|
100
|
+
? new GraphQLObjectType({
|
|
101
|
+
name: 'server_info_websocket_graphql',
|
|
102
|
+
fields: {
|
|
103
|
+
authentication: {
|
|
104
|
+
type: new GraphQLEnumType({
|
|
105
|
+
name: 'server_info_websocket_graphql_authentication',
|
|
106
|
+
values: {
|
|
107
|
+
public: { value: 'public' },
|
|
108
|
+
handshake: { value: 'handshake' },
|
|
109
|
+
strict: { value: 'strict' },
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
path: { type: GraphQLString },
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
: GraphQLBoolean,
|
|
117
|
+
},
|
|
118
|
+
heartbeat: {
|
|
119
|
+
type: toBoolean(env['WEBSOCKETS_HEARTBEAT_ENABLED']) ? GraphQLInt : GraphQLBoolean,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
}),
|
|
123
|
+
}
|
|
124
|
+
: GraphQLBoolean,
|
|
125
|
+
queryLimit: {
|
|
126
|
+
type: new GraphQLObjectType({
|
|
127
|
+
name: 'server_info_query_limit',
|
|
128
|
+
fields: {
|
|
129
|
+
default: { type: GraphQLInt },
|
|
130
|
+
max: { type: GraphQLInt },
|
|
131
|
+
},
|
|
132
|
+
}),
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/** Globally available query */
|
|
137
|
+
schemaComposer.Query.addFields({
|
|
138
|
+
server_specs_oas: {
|
|
139
|
+
type: GraphQLJSON,
|
|
140
|
+
resolve: async () => {
|
|
141
|
+
const service = new SpecificationService({ schema: gql.schema, accountability: gql.accountability });
|
|
142
|
+
return await service.oas.generate();
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
server_specs_graphql: {
|
|
146
|
+
type: GraphQLString,
|
|
147
|
+
args: {
|
|
148
|
+
scope: new GraphQLEnumType({
|
|
149
|
+
name: 'graphql_sdl_scope',
|
|
150
|
+
values: {
|
|
151
|
+
items: { value: 'items' },
|
|
152
|
+
system: { value: 'system' },
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
},
|
|
156
|
+
resolve: async (_, args) => {
|
|
157
|
+
const service = new GraphQLService({
|
|
158
|
+
schema: gql.schema,
|
|
159
|
+
accountability: gql.accountability,
|
|
160
|
+
scope: args['scope'] ?? 'items',
|
|
161
|
+
});
|
|
162
|
+
return await generateSchema(service, 'sdl');
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
server_ping: {
|
|
166
|
+
type: GraphQLString,
|
|
167
|
+
resolve: () => 'pong',
|
|
168
|
+
},
|
|
169
|
+
server_info: {
|
|
170
|
+
type: ServerInfo,
|
|
171
|
+
resolve: async () => {
|
|
172
|
+
const service = new ServerService({
|
|
173
|
+
accountability: gql.accountability,
|
|
174
|
+
schema: gql.schema,
|
|
175
|
+
});
|
|
176
|
+
return await service.serverInfo();
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
server_health: {
|
|
180
|
+
type: GraphQLJSON,
|
|
181
|
+
resolve: async () => {
|
|
182
|
+
const service = new ServerService({
|
|
183
|
+
accountability: gql.accountability,
|
|
184
|
+
schema: gql.schema,
|
|
185
|
+
});
|
|
186
|
+
return await service.health();
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
const Collection = schemaComposer.createObjectTC({
|
|
191
|
+
name: 'directus_collections',
|
|
192
|
+
});
|
|
193
|
+
const Field = schemaComposer.createObjectTC({
|
|
194
|
+
name: 'directus_fields',
|
|
195
|
+
});
|
|
196
|
+
const Relation = schemaComposer.createObjectTC({
|
|
197
|
+
name: 'directus_relations',
|
|
198
|
+
});
|
|
199
|
+
const Extension = schemaComposer.createObjectTC({
|
|
200
|
+
name: 'directus_extensions',
|
|
201
|
+
});
|
|
202
|
+
const composers = {
|
|
203
|
+
Collection,
|
|
204
|
+
Field,
|
|
205
|
+
Relation,
|
|
206
|
+
Extension,
|
|
207
|
+
};
|
|
208
|
+
if ('directus_collections' in schema.read.collections) {
|
|
209
|
+
Collection.addFields({
|
|
210
|
+
collection: GraphQLString,
|
|
211
|
+
meta: schemaComposer.createObjectTC({
|
|
212
|
+
name: 'directus_collections_meta',
|
|
213
|
+
fields: Object.values(schema.read.collections['directus_collections'].fields).reduce((acc, field) => {
|
|
214
|
+
acc[field.field] = {
|
|
215
|
+
type: field.nullable
|
|
216
|
+
? getGraphQLType(field.type, field.special)
|
|
217
|
+
: new GraphQLNonNull(getGraphQLType(field.type, field.special)),
|
|
218
|
+
description: field.note,
|
|
219
|
+
};
|
|
220
|
+
return acc;
|
|
221
|
+
}, {}),
|
|
222
|
+
}),
|
|
223
|
+
schema: schemaComposer.createObjectTC({
|
|
224
|
+
name: 'directus_collections_schema',
|
|
225
|
+
fields: {
|
|
226
|
+
name: GraphQLString,
|
|
227
|
+
comment: GraphQLString,
|
|
228
|
+
},
|
|
229
|
+
}),
|
|
230
|
+
});
|
|
231
|
+
schemaComposer.Query.addFields({
|
|
232
|
+
collections: {
|
|
233
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Collection.getType()))),
|
|
234
|
+
resolve: async () => {
|
|
235
|
+
const collectionsService = new CollectionsService({
|
|
236
|
+
accountability: gql.accountability,
|
|
237
|
+
schema: gql.schema,
|
|
238
|
+
});
|
|
239
|
+
return await collectionsService.readByQuery();
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
collections_by_name: {
|
|
243
|
+
type: Collection,
|
|
244
|
+
args: {
|
|
245
|
+
name: new GraphQLNonNull(GraphQLString),
|
|
246
|
+
},
|
|
247
|
+
resolve: async (_, args) => {
|
|
248
|
+
const collectionsService = new CollectionsService({
|
|
249
|
+
accountability: gql.accountability,
|
|
250
|
+
schema: gql.schema,
|
|
251
|
+
});
|
|
252
|
+
return await collectionsService.readOne(args['name']);
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
if ('directus_fields' in schema.read.collections) {
|
|
258
|
+
Field.addFields({
|
|
259
|
+
collection: GraphQLString,
|
|
260
|
+
field: GraphQLString,
|
|
261
|
+
type: GraphQLString,
|
|
262
|
+
meta: schemaComposer.createObjectTC({
|
|
263
|
+
name: 'directus_fields_meta',
|
|
264
|
+
fields: Object.values(schema.read.collections['directus_fields'].fields).reduce((acc, field) => {
|
|
265
|
+
acc[field.field] = {
|
|
266
|
+
type: field.nullable
|
|
267
|
+
? getGraphQLType(field.type, field.special)
|
|
268
|
+
: new GraphQLNonNull(getGraphQLType(field.type, field.special)),
|
|
269
|
+
description: field.note,
|
|
270
|
+
};
|
|
271
|
+
return acc;
|
|
272
|
+
}, {}),
|
|
273
|
+
}),
|
|
274
|
+
schema: schemaComposer.createObjectTC({
|
|
275
|
+
name: 'directus_fields_schema',
|
|
276
|
+
fields: {
|
|
277
|
+
name: GraphQLString,
|
|
278
|
+
table: GraphQLString,
|
|
279
|
+
data_type: GraphQLString,
|
|
280
|
+
default_value: GraphQLString,
|
|
281
|
+
max_length: GraphQLInt,
|
|
282
|
+
numeric_precision: GraphQLInt,
|
|
283
|
+
numeric_scale: GraphQLInt,
|
|
284
|
+
is_generated: GraphQLBoolean,
|
|
285
|
+
generation_expression: GraphQLString,
|
|
286
|
+
is_indexed: GraphQLBoolean,
|
|
287
|
+
is_nullable: GraphQLBoolean,
|
|
288
|
+
is_unique: GraphQLBoolean,
|
|
289
|
+
is_primary_key: GraphQLBoolean,
|
|
290
|
+
has_auto_increment: GraphQLBoolean,
|
|
291
|
+
foreign_key_column: GraphQLString,
|
|
292
|
+
foreign_key_table: GraphQLString,
|
|
293
|
+
comment: GraphQLString,
|
|
294
|
+
},
|
|
295
|
+
}),
|
|
296
|
+
});
|
|
297
|
+
schemaComposer.Query.addFields({
|
|
298
|
+
fields: {
|
|
299
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Field.getType()))),
|
|
300
|
+
resolve: async () => {
|
|
301
|
+
const service = new FieldsService({
|
|
302
|
+
accountability: gql.accountability,
|
|
303
|
+
schema: gql.schema,
|
|
304
|
+
});
|
|
305
|
+
return await service.readAll();
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
fields_in_collection: {
|
|
309
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Field.getType()))),
|
|
310
|
+
args: {
|
|
311
|
+
collection: new GraphQLNonNull(GraphQLString),
|
|
312
|
+
},
|
|
313
|
+
resolve: async (_, args) => {
|
|
314
|
+
const service = new FieldsService({
|
|
315
|
+
accountability: gql.accountability,
|
|
316
|
+
schema: gql.schema,
|
|
317
|
+
});
|
|
318
|
+
return await service.readAll(args['collection']);
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
fields_by_name: {
|
|
322
|
+
type: Field,
|
|
323
|
+
args: {
|
|
324
|
+
collection: new GraphQLNonNull(GraphQLString),
|
|
325
|
+
field: new GraphQLNonNull(GraphQLString),
|
|
326
|
+
},
|
|
327
|
+
resolve: async (_, args) => {
|
|
328
|
+
const service = new FieldsService({
|
|
329
|
+
accountability: gql.accountability,
|
|
330
|
+
schema: gql.schema,
|
|
331
|
+
});
|
|
332
|
+
return await service.readOne(args['collection'], args['field']);
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
if ('directus_relations' in schema.read.collections) {
|
|
338
|
+
Relation.addFields({
|
|
339
|
+
collection: GraphQLString,
|
|
340
|
+
field: GraphQLString,
|
|
341
|
+
related_collection: GraphQLString,
|
|
342
|
+
schema: schemaComposer.createObjectTC({
|
|
343
|
+
name: 'directus_relations_schema',
|
|
344
|
+
fields: {
|
|
345
|
+
table: new GraphQLNonNull(GraphQLString),
|
|
346
|
+
column: new GraphQLNonNull(GraphQLString),
|
|
347
|
+
foreign_key_table: new GraphQLNonNull(GraphQLString),
|
|
348
|
+
foreign_key_column: new GraphQLNonNull(GraphQLString),
|
|
349
|
+
constraint_name: GraphQLString,
|
|
350
|
+
on_update: new GraphQLNonNull(GraphQLString),
|
|
351
|
+
on_delete: new GraphQLNonNull(GraphQLString),
|
|
352
|
+
},
|
|
353
|
+
}),
|
|
354
|
+
meta: schemaComposer.createObjectTC({
|
|
355
|
+
name: 'directus_relations_meta',
|
|
356
|
+
fields: Object.values(schema.read.collections['directus_relations'].fields).reduce((acc, field) => {
|
|
357
|
+
acc[field.field] = {
|
|
358
|
+
type: getGraphQLType(field.type, field.special),
|
|
359
|
+
description: field.note,
|
|
360
|
+
};
|
|
361
|
+
return acc;
|
|
362
|
+
}, {}),
|
|
363
|
+
}),
|
|
364
|
+
});
|
|
365
|
+
schemaComposer.Query.addFields({
|
|
366
|
+
relations: {
|
|
367
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Relation.getType()))),
|
|
368
|
+
resolve: async () => {
|
|
369
|
+
const service = new RelationsService({
|
|
370
|
+
accountability: gql.accountability,
|
|
371
|
+
schema: gql.schema,
|
|
372
|
+
});
|
|
373
|
+
return await service.readAll();
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
relations_in_collection: {
|
|
377
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Relation.getType()))),
|
|
378
|
+
args: {
|
|
379
|
+
collection: new GraphQLNonNull(GraphQLString),
|
|
380
|
+
},
|
|
381
|
+
resolve: async (_, args) => {
|
|
382
|
+
const service = new RelationsService({
|
|
383
|
+
accountability: gql.accountability,
|
|
384
|
+
schema: gql.schema,
|
|
385
|
+
});
|
|
386
|
+
return await service.readAll(args['collection']);
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
relations_by_name: {
|
|
390
|
+
type: Relation,
|
|
391
|
+
args: {
|
|
392
|
+
collection: new GraphQLNonNull(GraphQLString),
|
|
393
|
+
field: new GraphQLNonNull(GraphQLString),
|
|
394
|
+
},
|
|
395
|
+
resolve: async (_, args) => {
|
|
396
|
+
const service = new RelationsService({
|
|
397
|
+
accountability: gql.accountability,
|
|
398
|
+
schema: gql.schema,
|
|
399
|
+
});
|
|
400
|
+
return await service.readOne(args['collection'], args['field']);
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
resolveSystemAdmin(gql, schemaComposer, composers);
|
|
406
|
+
if ('directus_users' in schema.read.collections) {
|
|
407
|
+
schemaComposer.Query.addFields({
|
|
408
|
+
users_me: {
|
|
409
|
+
type: ReadCollectionTypes['directus_users'],
|
|
410
|
+
resolve: async (_, args, __, info) => {
|
|
411
|
+
if (!gql.accountability?.user)
|
|
412
|
+
return null;
|
|
413
|
+
const service = new UsersService({ schema: gql.schema, accountability: gql.accountability });
|
|
414
|
+
const selections = replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
|
|
415
|
+
const query = getQuery(args, selections || [], info.variableValues, gql.accountability);
|
|
416
|
+
return await service.readOne(gql.accountability.user, query);
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
if ('directus_permissions' in schema.read.collections) {
|
|
422
|
+
schemaComposer.Query.addFields({
|
|
423
|
+
permissions_me: {
|
|
424
|
+
type: schemaComposer.createScalarTC({
|
|
425
|
+
name: 'permissions_me_type',
|
|
426
|
+
parseValue: (value) => value,
|
|
427
|
+
serialize: (value) => value,
|
|
428
|
+
}),
|
|
429
|
+
resolve: async (_, _args, __, _info) => {
|
|
430
|
+
if (!gql.accountability?.user && !gql.accountability?.role)
|
|
431
|
+
return null;
|
|
432
|
+
const result = await fetchAccountabilityCollectionAccess(gql.accountability, {
|
|
433
|
+
schema: gql.schema,
|
|
434
|
+
knex: getDatabase(),
|
|
435
|
+
});
|
|
436
|
+
return result;
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
if ('directus_roles' in schema.read.collections) {
|
|
442
|
+
schemaComposer.Query.addFields({
|
|
443
|
+
roles_me: {
|
|
444
|
+
type: ReadCollectionTypes['directus_roles'].List,
|
|
445
|
+
resolve: async (_, args, __, info) => {
|
|
446
|
+
if (!gql.accountability?.user && !gql.accountability?.role)
|
|
447
|
+
return null;
|
|
448
|
+
const service = new RolesService({
|
|
449
|
+
accountability: gql.accountability,
|
|
450
|
+
schema: gql.schema,
|
|
451
|
+
});
|
|
452
|
+
const selections = replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
|
|
453
|
+
const query = getQuery(args, selections || [], info.variableValues, gql.accountability);
|
|
454
|
+
query.limit = -1;
|
|
455
|
+
const roles = await service.readMany(gql.accountability.roles, query);
|
|
456
|
+
return roles;
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
if ('directus_policies' in schema.read.collections) {
|
|
462
|
+
schemaComposer.Query.addFields({
|
|
463
|
+
policies_me_globals: {
|
|
464
|
+
type: schemaComposer.createObjectTC({
|
|
465
|
+
name: 'policy_me_globals_type',
|
|
466
|
+
fields: {
|
|
467
|
+
enforce_tfa: 'Boolean',
|
|
468
|
+
app_access: 'Boolean',
|
|
469
|
+
admin_access: 'Boolean',
|
|
470
|
+
},
|
|
471
|
+
}),
|
|
472
|
+
resolve: async (_, _args, __, _info) => {
|
|
473
|
+
if (!gql.accountability?.user && !gql.accountability?.role)
|
|
474
|
+
return null;
|
|
475
|
+
const result = await fetchAccountabilityPolicyGlobals(gql.accountability, {
|
|
476
|
+
schema: gql.schema,
|
|
477
|
+
knex: getDatabase(),
|
|
478
|
+
});
|
|
479
|
+
return result;
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
if ('directus_users' in schema.update.collections && gql.accountability?.user) {
|
|
485
|
+
schemaComposer.Mutation.addFields({
|
|
486
|
+
update_users_me: {
|
|
487
|
+
type: ReadCollectionTypes['directus_users'],
|
|
488
|
+
args: {
|
|
489
|
+
data: toInputObjectType(UpdateCollectionTypes['directus_users']),
|
|
490
|
+
},
|
|
491
|
+
resolve: async (_, args, __, info) => {
|
|
492
|
+
if (!gql.accountability?.user)
|
|
493
|
+
return null;
|
|
494
|
+
const service = new UsersService({
|
|
495
|
+
schema: gql.schema,
|
|
496
|
+
accountability: gql.accountability,
|
|
497
|
+
});
|
|
498
|
+
await service.updateOne(gql.accountability.user, args['data']);
|
|
499
|
+
if ('directus_users' in ReadCollectionTypes) {
|
|
500
|
+
const selections = replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
|
|
501
|
+
const query = getQuery(args, selections || [], info.variableValues, gql.accountability);
|
|
502
|
+
return await service.readOne(gql.accountability.user, query);
|
|
503
|
+
}
|
|
504
|
+
return true;
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
if ('directus_files' in schema.create.collections) {
|
|
510
|
+
schemaComposer.Mutation.addFields({
|
|
511
|
+
import_file: {
|
|
512
|
+
type: ReadCollectionTypes['directus_files'] ?? GraphQLBoolean,
|
|
513
|
+
args: {
|
|
514
|
+
url: new GraphQLNonNull(GraphQLString),
|
|
515
|
+
data: toInputObjectType(CreateCollectionTypes['directus_files']).setTypeName('create_directus_files_input'),
|
|
516
|
+
},
|
|
517
|
+
resolve: async (_, args, __, info) => {
|
|
518
|
+
const service = new FilesService({
|
|
519
|
+
accountability: gql.accountability,
|
|
520
|
+
schema: gql.schema,
|
|
521
|
+
});
|
|
522
|
+
const primaryKey = await service.importOne(args['url'], args['data']);
|
|
523
|
+
if ('directus_files' in ReadCollectionTypes) {
|
|
524
|
+
const selections = replaceFragmentsInSelections(info.fieldNodes[0]?.selectionSet?.selections, info.fragments);
|
|
525
|
+
const query = getQuery(args, selections || [], info.variableValues, gql.accountability);
|
|
526
|
+
return await service.readOne(primaryKey, query);
|
|
527
|
+
}
|
|
528
|
+
return true;
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
if ('directus_users' in schema.create.collections) {
|
|
534
|
+
schemaComposer.Mutation.addFields({
|
|
535
|
+
users_invite: {
|
|
536
|
+
type: GraphQLBoolean,
|
|
537
|
+
args: {
|
|
538
|
+
email: new GraphQLNonNull(GraphQLString),
|
|
539
|
+
role: new GraphQLNonNull(GraphQLString),
|
|
540
|
+
invite_url: GraphQLString,
|
|
541
|
+
},
|
|
542
|
+
resolve: async (_, args) => {
|
|
543
|
+
const service = new UsersService({
|
|
544
|
+
accountability: gql.accountability,
|
|
545
|
+
schema: gql.schema,
|
|
546
|
+
});
|
|
547
|
+
await service.inviteUser(args['email'], args['role'], args['invite_url'] || null);
|
|
548
|
+
return true;
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
return schemaComposer;
|
|
554
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SchemaComposer } from 'graphql-compose';
|
|
2
|
+
import { ObjectTypeComposer } from 'graphql-compose';
|
|
3
|
+
import { type GQLScope } from '../index.js';
|
|
4
|
+
import { type InconsistentFields, type Schema } from './index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Construct an object of types for every collection, using the permitted fields per action type
|
|
7
|
+
* as it's fields.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getTypes(schemaComposer: SchemaComposer, scope: GQLScope, schema: Schema, inconsistentFields: InconsistentFields, action: 'read' | 'create' | 'update' | 'delete'): {
|
|
10
|
+
CollectionTypes: Record<string, ObjectTypeComposer<any, any>>;
|
|
11
|
+
VersionTypes: Record<string, ObjectTypeComposer<any, any>>;
|
|
12
|
+
};
|