@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,435 @@
|
|
|
1
|
+
import { useEnv } from '@directus/env';
|
|
2
|
+
import { ErrorCode, ForbiddenError, InvalidPayloadError, isDirectusError } from '@directus/errors';
|
|
3
|
+
import argon2 from 'argon2';
|
|
4
|
+
import { GraphQLBoolean, GraphQLEnumType, GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLObjectType, GraphQLString, } from 'graphql';
|
|
5
|
+
import { SchemaComposer } from 'graphql-compose';
|
|
6
|
+
import { clearSystemCache, getCache } from '../../../cache.js';
|
|
7
|
+
import { DEFAULT_AUTH_PROVIDER, REFRESH_COOKIE_OPTIONS, SESSION_COOKIE_OPTIONS } from '../../../constants.js';
|
|
8
|
+
import { rateLimiter } from '../../../middleware/rate-limiter-registration.js';
|
|
9
|
+
import { createDefaultAccountability } from '../../../permissions/utils/create-default-accountability.js';
|
|
10
|
+
import { generateHash } from '../../../utils/generate-hash.js';
|
|
11
|
+
import { getIPFromReq } from '../../../utils/get-ip-from-req.js';
|
|
12
|
+
import { getSecret } from '../../../utils/get-secret.js';
|
|
13
|
+
import isDirectusJWT from '../../../utils/is-directus-jwt.js';
|
|
14
|
+
import { verifyAccessJWT } from '../../../utils/jwt.js';
|
|
15
|
+
import { AuthenticationService } from '../../authentication.js';
|
|
16
|
+
import { RevisionsService } from '../../revisions.js';
|
|
17
|
+
import { TFAService } from '../../tfa.js';
|
|
18
|
+
import { UsersService } from '../../users.js';
|
|
19
|
+
import { UtilsService } from '../../utils.js';
|
|
20
|
+
import { GraphQLService } from '../index.js';
|
|
21
|
+
import { GraphQLBigInt } from '../types/bigint.js';
|
|
22
|
+
import { GraphQLVoid } from '../types/void.js';
|
|
23
|
+
const env = useEnv();
|
|
24
|
+
/**
|
|
25
|
+
* Globally available mutations
|
|
26
|
+
*/
|
|
27
|
+
export function globalResolvers(gql, schemaComposer) {
|
|
28
|
+
const AuthTokens = schemaComposer.createObjectTC({
|
|
29
|
+
name: 'auth_tokens',
|
|
30
|
+
fields: {
|
|
31
|
+
access_token: GraphQLString,
|
|
32
|
+
expires: GraphQLBigInt,
|
|
33
|
+
refresh_token: GraphQLString,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const AuthMode = new GraphQLEnumType({
|
|
37
|
+
name: 'auth_mode',
|
|
38
|
+
values: {
|
|
39
|
+
json: { value: 'json' },
|
|
40
|
+
cookie: { value: 'cookie' },
|
|
41
|
+
session: { value: 'session' },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
schemaComposer.Mutation.addFields({
|
|
45
|
+
auth_login: {
|
|
46
|
+
type: AuthTokens,
|
|
47
|
+
args: {
|
|
48
|
+
email: new GraphQLNonNull(GraphQLString),
|
|
49
|
+
password: new GraphQLNonNull(GraphQLString),
|
|
50
|
+
mode: AuthMode,
|
|
51
|
+
otp: GraphQLString,
|
|
52
|
+
},
|
|
53
|
+
resolve: async (_, args, { req, res }) => {
|
|
54
|
+
const accountability = createDefaultAccountability();
|
|
55
|
+
if (req?.ip)
|
|
56
|
+
accountability.ip = req.ip;
|
|
57
|
+
const userAgent = req?.get('user-agent');
|
|
58
|
+
if (userAgent)
|
|
59
|
+
accountability.userAgent = userAgent;
|
|
60
|
+
const origin = req?.get('origin');
|
|
61
|
+
if (origin)
|
|
62
|
+
accountability.origin = origin;
|
|
63
|
+
const authenticationService = new AuthenticationService({
|
|
64
|
+
accountability: accountability,
|
|
65
|
+
schema: gql.schema,
|
|
66
|
+
});
|
|
67
|
+
const mode = args['mode'] ?? 'json';
|
|
68
|
+
const { accessToken, refreshToken, expires } = await authenticationService.login(DEFAULT_AUTH_PROVIDER, args, {
|
|
69
|
+
session: mode === 'session',
|
|
70
|
+
otp: args?.otp,
|
|
71
|
+
});
|
|
72
|
+
const payload = { expires };
|
|
73
|
+
if (mode === 'json') {
|
|
74
|
+
payload.refresh_token = refreshToken;
|
|
75
|
+
payload.access_token = accessToken;
|
|
76
|
+
}
|
|
77
|
+
if (mode === 'cookie') {
|
|
78
|
+
res?.cookie(env['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, REFRESH_COOKIE_OPTIONS);
|
|
79
|
+
payload.access_token = accessToken;
|
|
80
|
+
}
|
|
81
|
+
if (mode === 'session') {
|
|
82
|
+
res?.cookie(env['SESSION_COOKIE_NAME'], accessToken, SESSION_COOKIE_OPTIONS);
|
|
83
|
+
}
|
|
84
|
+
return payload;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
auth_refresh: {
|
|
88
|
+
type: AuthTokens,
|
|
89
|
+
args: {
|
|
90
|
+
refresh_token: GraphQLString,
|
|
91
|
+
mode: AuthMode,
|
|
92
|
+
},
|
|
93
|
+
resolve: async (_, args, { req, res }) => {
|
|
94
|
+
const accountability = createDefaultAccountability();
|
|
95
|
+
if (req?.ip)
|
|
96
|
+
accountability.ip = req.ip;
|
|
97
|
+
const userAgent = req?.get('user-agent');
|
|
98
|
+
if (userAgent)
|
|
99
|
+
accountability.userAgent = userAgent;
|
|
100
|
+
const origin = req?.get('origin');
|
|
101
|
+
if (origin)
|
|
102
|
+
accountability.origin = origin;
|
|
103
|
+
const authenticationService = new AuthenticationService({
|
|
104
|
+
accountability: accountability,
|
|
105
|
+
schema: gql.schema,
|
|
106
|
+
});
|
|
107
|
+
const mode = args['mode'] ?? 'json';
|
|
108
|
+
let currentRefreshToken;
|
|
109
|
+
if (mode === 'json') {
|
|
110
|
+
currentRefreshToken = args['refresh_token'];
|
|
111
|
+
}
|
|
112
|
+
else if (mode === 'cookie') {
|
|
113
|
+
currentRefreshToken = req?.cookies[env['REFRESH_TOKEN_COOKIE_NAME']];
|
|
114
|
+
}
|
|
115
|
+
else if (mode === 'session') {
|
|
116
|
+
const token = req?.cookies[env['SESSION_COOKIE_NAME']];
|
|
117
|
+
if (isDirectusJWT(token)) {
|
|
118
|
+
const payload = verifyAccessJWT(token, getSecret());
|
|
119
|
+
currentRefreshToken = payload.session;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!currentRefreshToken) {
|
|
123
|
+
throw new InvalidPayloadError({
|
|
124
|
+
reason: `The refresh token is required in either the payload or cookie`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const { accessToken, refreshToken, expires } = await authenticationService.refresh(currentRefreshToken, {
|
|
128
|
+
session: mode === 'session',
|
|
129
|
+
});
|
|
130
|
+
const payload = { expires };
|
|
131
|
+
if (mode === 'json') {
|
|
132
|
+
payload.refresh_token = refreshToken;
|
|
133
|
+
payload.access_token = accessToken;
|
|
134
|
+
}
|
|
135
|
+
if (mode === 'cookie') {
|
|
136
|
+
res?.cookie(env['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, REFRESH_COOKIE_OPTIONS);
|
|
137
|
+
payload.access_token = accessToken;
|
|
138
|
+
}
|
|
139
|
+
if (mode === 'session') {
|
|
140
|
+
res?.cookie(env['SESSION_COOKIE_NAME'], accessToken, SESSION_COOKIE_OPTIONS);
|
|
141
|
+
}
|
|
142
|
+
return payload;
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
auth_logout: {
|
|
146
|
+
type: GraphQLBoolean,
|
|
147
|
+
args: {
|
|
148
|
+
refresh_token: GraphQLString,
|
|
149
|
+
mode: AuthMode,
|
|
150
|
+
},
|
|
151
|
+
resolve: async (_, args, { req, res }) => {
|
|
152
|
+
const accountability = createDefaultAccountability();
|
|
153
|
+
if (req?.ip)
|
|
154
|
+
accountability.ip = req.ip;
|
|
155
|
+
const userAgent = req?.get('user-agent');
|
|
156
|
+
if (userAgent)
|
|
157
|
+
accountability.userAgent = userAgent;
|
|
158
|
+
const origin = req?.get('origin');
|
|
159
|
+
if (origin)
|
|
160
|
+
accountability.origin = origin;
|
|
161
|
+
const authenticationService = new AuthenticationService({
|
|
162
|
+
accountability: accountability,
|
|
163
|
+
schema: gql.schema,
|
|
164
|
+
});
|
|
165
|
+
const mode = args['mode'] ?? 'json';
|
|
166
|
+
let currentRefreshToken;
|
|
167
|
+
if (mode === 'json') {
|
|
168
|
+
currentRefreshToken = args['refresh_token'];
|
|
169
|
+
}
|
|
170
|
+
else if (mode === 'cookie') {
|
|
171
|
+
currentRefreshToken = req?.cookies[env['REFRESH_TOKEN_COOKIE_NAME']];
|
|
172
|
+
}
|
|
173
|
+
else if (mode === 'session') {
|
|
174
|
+
const token = req?.cookies[env['SESSION_COOKIE_NAME']];
|
|
175
|
+
if (isDirectusJWT(token)) {
|
|
176
|
+
const payload = verifyAccessJWT(token, getSecret());
|
|
177
|
+
currentRefreshToken = payload.session;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (!currentRefreshToken) {
|
|
181
|
+
throw new InvalidPayloadError({
|
|
182
|
+
reason: `The refresh token is required in either the payload or cookie`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
await authenticationService.logout(currentRefreshToken);
|
|
186
|
+
if (req?.cookies[env['REFRESH_TOKEN_COOKIE_NAME']]) {
|
|
187
|
+
res?.clearCookie(env['REFRESH_TOKEN_COOKIE_NAME'], REFRESH_COOKIE_OPTIONS);
|
|
188
|
+
}
|
|
189
|
+
if (req?.cookies[env['SESSION_COOKIE_NAME']]) {
|
|
190
|
+
res?.clearCookie(env['SESSION_COOKIE_NAME'], SESSION_COOKIE_OPTIONS);
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
auth_password_request: {
|
|
196
|
+
type: GraphQLBoolean,
|
|
197
|
+
args: {
|
|
198
|
+
email: new GraphQLNonNull(GraphQLString),
|
|
199
|
+
reset_url: GraphQLString,
|
|
200
|
+
},
|
|
201
|
+
resolve: async (_, args, { req }) => {
|
|
202
|
+
const accountability = createDefaultAccountability();
|
|
203
|
+
if (req?.ip)
|
|
204
|
+
accountability.ip = req.ip;
|
|
205
|
+
const userAgent = req?.get('user-agent');
|
|
206
|
+
if (userAgent)
|
|
207
|
+
accountability.userAgent = userAgent;
|
|
208
|
+
const origin = req?.get('origin');
|
|
209
|
+
if (origin)
|
|
210
|
+
accountability.origin = origin;
|
|
211
|
+
const service = new UsersService({ accountability, schema: gql.schema });
|
|
212
|
+
try {
|
|
213
|
+
await service.requestPasswordReset(args['email'], args['reset_url'] || null);
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
if (isDirectusError(err, ErrorCode.InvalidPayload)) {
|
|
217
|
+
throw err;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
auth_password_reset: {
|
|
224
|
+
type: GraphQLBoolean,
|
|
225
|
+
args: {
|
|
226
|
+
token: new GraphQLNonNull(GraphQLString),
|
|
227
|
+
password: new GraphQLNonNull(GraphQLString),
|
|
228
|
+
},
|
|
229
|
+
resolve: async (_, args, { req }) => {
|
|
230
|
+
const accountability = createDefaultAccountability();
|
|
231
|
+
if (req?.ip)
|
|
232
|
+
accountability.ip = req.ip;
|
|
233
|
+
const userAgent = req?.get('user-agent');
|
|
234
|
+
if (userAgent)
|
|
235
|
+
accountability.userAgent = userAgent;
|
|
236
|
+
const origin = req?.get('origin');
|
|
237
|
+
if (origin)
|
|
238
|
+
accountability.origin = origin;
|
|
239
|
+
const service = new UsersService({ accountability, schema: gql.schema });
|
|
240
|
+
await service.resetPassword(args['token'], args['password']);
|
|
241
|
+
return true;
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
users_me_tfa_generate: {
|
|
245
|
+
type: new GraphQLObjectType({
|
|
246
|
+
name: 'users_me_tfa_generate_data',
|
|
247
|
+
fields: {
|
|
248
|
+
secret: { type: GraphQLString },
|
|
249
|
+
otpauth_url: { type: GraphQLString },
|
|
250
|
+
},
|
|
251
|
+
}),
|
|
252
|
+
args: {
|
|
253
|
+
password: new GraphQLNonNull(GraphQLString),
|
|
254
|
+
},
|
|
255
|
+
resolve: async (_, args) => {
|
|
256
|
+
if (!gql.accountability?.user)
|
|
257
|
+
return null;
|
|
258
|
+
const service = new TFAService({
|
|
259
|
+
accountability: gql.accountability,
|
|
260
|
+
schema: gql.schema,
|
|
261
|
+
});
|
|
262
|
+
const authService = new AuthenticationService({
|
|
263
|
+
accountability: gql.accountability,
|
|
264
|
+
schema: gql.schema,
|
|
265
|
+
});
|
|
266
|
+
await authService.verifyPassword(gql.accountability.user, args['password']);
|
|
267
|
+
const { url, secret } = await service.generateTFA(gql.accountability.user);
|
|
268
|
+
return { secret, otpauth_url: url };
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
users_me_tfa_enable: {
|
|
272
|
+
type: GraphQLBoolean,
|
|
273
|
+
args: {
|
|
274
|
+
otp: new GraphQLNonNull(GraphQLString),
|
|
275
|
+
secret: new GraphQLNonNull(GraphQLString),
|
|
276
|
+
},
|
|
277
|
+
resolve: async (_, args) => {
|
|
278
|
+
if (!gql.accountability?.user)
|
|
279
|
+
return null;
|
|
280
|
+
const service = new TFAService({
|
|
281
|
+
accountability: gql.accountability,
|
|
282
|
+
schema: gql.schema,
|
|
283
|
+
});
|
|
284
|
+
await service.enableTFA(gql.accountability.user, args['otp'], args['secret']);
|
|
285
|
+
return true;
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
users_me_tfa_disable: {
|
|
289
|
+
type: GraphQLBoolean,
|
|
290
|
+
args: {
|
|
291
|
+
otp: new GraphQLNonNull(GraphQLString),
|
|
292
|
+
},
|
|
293
|
+
resolve: async (_, args) => {
|
|
294
|
+
if (!gql.accountability?.user)
|
|
295
|
+
return null;
|
|
296
|
+
const service = new TFAService({
|
|
297
|
+
accountability: gql.accountability,
|
|
298
|
+
schema: gql.schema,
|
|
299
|
+
});
|
|
300
|
+
const otpValid = await service.verifyOTP(gql.accountability.user, args['otp']);
|
|
301
|
+
if (otpValid === false) {
|
|
302
|
+
throw new InvalidPayloadError({ reason: `"otp" is invalid` });
|
|
303
|
+
}
|
|
304
|
+
await service.disableTFA(gql.accountability.user);
|
|
305
|
+
return true;
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
utils_random_string: {
|
|
309
|
+
type: GraphQLString,
|
|
310
|
+
args: {
|
|
311
|
+
length: GraphQLInt,
|
|
312
|
+
},
|
|
313
|
+
resolve: async (_, args) => {
|
|
314
|
+
const { nanoid } = await import('nanoid');
|
|
315
|
+
if (args['length'] !== undefined && (args['length'] < 1 || args['length'] > 500)) {
|
|
316
|
+
throw new InvalidPayloadError({ reason: `"length" must be between 1 and 500` });
|
|
317
|
+
}
|
|
318
|
+
return nanoid(args['length'] ? args['length'] : 32);
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
utils_hash_generate: {
|
|
322
|
+
type: GraphQLString,
|
|
323
|
+
args: {
|
|
324
|
+
string: new GraphQLNonNull(GraphQLString),
|
|
325
|
+
},
|
|
326
|
+
resolve: async (_, args) => {
|
|
327
|
+
return await generateHash(args['string']);
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
utils_hash_verify: {
|
|
331
|
+
type: GraphQLBoolean,
|
|
332
|
+
args: {
|
|
333
|
+
string: new GraphQLNonNull(GraphQLString),
|
|
334
|
+
hash: new GraphQLNonNull(GraphQLString),
|
|
335
|
+
},
|
|
336
|
+
resolve: async (_, args) => {
|
|
337
|
+
return await argon2.verify(args['hash'], args['string']);
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
utils_sort: {
|
|
341
|
+
type: GraphQLBoolean,
|
|
342
|
+
args: {
|
|
343
|
+
collection: new GraphQLNonNull(GraphQLString),
|
|
344
|
+
item: new GraphQLNonNull(GraphQLID),
|
|
345
|
+
to: new GraphQLNonNull(GraphQLID),
|
|
346
|
+
},
|
|
347
|
+
resolve: async (_, args) => {
|
|
348
|
+
const service = new UtilsService({
|
|
349
|
+
accountability: gql.accountability,
|
|
350
|
+
schema: gql.schema,
|
|
351
|
+
});
|
|
352
|
+
const { item, to } = args;
|
|
353
|
+
await service.sort(args['collection'], { item, to });
|
|
354
|
+
return true;
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
utils_revert: {
|
|
358
|
+
type: GraphQLBoolean,
|
|
359
|
+
args: {
|
|
360
|
+
revision: new GraphQLNonNull(GraphQLID),
|
|
361
|
+
},
|
|
362
|
+
resolve: async (_, args) => {
|
|
363
|
+
const service = new RevisionsService({
|
|
364
|
+
accountability: gql.accountability,
|
|
365
|
+
schema: gql.schema,
|
|
366
|
+
});
|
|
367
|
+
await service.revert(args['revision']);
|
|
368
|
+
return true;
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
utils_cache_clear: {
|
|
372
|
+
type: GraphQLVoid,
|
|
373
|
+
resolve: async () => {
|
|
374
|
+
if (gql.accountability?.admin !== true) {
|
|
375
|
+
throw new ForbiddenError();
|
|
376
|
+
}
|
|
377
|
+
const { cache } = getCache();
|
|
378
|
+
await cache?.clear();
|
|
379
|
+
await clearSystemCache();
|
|
380
|
+
return;
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
users_invite_accept: {
|
|
384
|
+
type: GraphQLBoolean,
|
|
385
|
+
args: {
|
|
386
|
+
token: new GraphQLNonNull(GraphQLString),
|
|
387
|
+
password: new GraphQLNonNull(GraphQLString),
|
|
388
|
+
},
|
|
389
|
+
resolve: async (_, args) => {
|
|
390
|
+
const service = new UsersService({
|
|
391
|
+
accountability: gql.accountability,
|
|
392
|
+
schema: gql.schema,
|
|
393
|
+
});
|
|
394
|
+
await service.acceptInvite(args['token'], args['password']);
|
|
395
|
+
return true;
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
users_register: {
|
|
399
|
+
type: GraphQLBoolean,
|
|
400
|
+
args: {
|
|
401
|
+
email: new GraphQLNonNull(GraphQLString),
|
|
402
|
+
password: new GraphQLNonNull(GraphQLString),
|
|
403
|
+
verification_url: GraphQLString,
|
|
404
|
+
first_name: GraphQLString,
|
|
405
|
+
last_name: GraphQLString,
|
|
406
|
+
},
|
|
407
|
+
resolve: async (_, args, { req }) => {
|
|
408
|
+
const service = new UsersService({ accountability: null, schema: gql.schema });
|
|
409
|
+
const ip = req ? getIPFromReq(req) : null;
|
|
410
|
+
if (ip) {
|
|
411
|
+
await rateLimiter.consume(ip);
|
|
412
|
+
}
|
|
413
|
+
await service.registerUser({
|
|
414
|
+
email: args.email,
|
|
415
|
+
password: args.password,
|
|
416
|
+
verification_url: args.verification_url,
|
|
417
|
+
first_name: args.first_name,
|
|
418
|
+
last_name: args.last_name,
|
|
419
|
+
});
|
|
420
|
+
return true;
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
users_register_verify: {
|
|
424
|
+
type: GraphQLBoolean,
|
|
425
|
+
args: {
|
|
426
|
+
token: new GraphQLNonNull(GraphQLString),
|
|
427
|
+
},
|
|
428
|
+
resolve: async (_, args) => {
|
|
429
|
+
const service = new UsersService({ accountability: null, schema: gql.schema });
|
|
430
|
+
await service.verifyRegistration(args.token);
|
|
431
|
+
return true;
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ObjectTypeComposer, SchemaComposer } from 'graphql-compose';
|
|
2
|
+
import type { GraphQLParams } from '../../../types/index.js';
|
|
3
|
+
import { GraphQLService } from '../index.js';
|
|
4
|
+
import { type CollectionTypes, type Schema } from '../schema/index.js';
|
|
5
|
+
export type BaseTypeComposers = {
|
|
6
|
+
Collection: ObjectTypeComposer<any, any>;
|
|
7
|
+
Field: ObjectTypeComposer<any, any>;
|
|
8
|
+
Relation: ObjectTypeComposer<any, any>;
|
|
9
|
+
Extension: ObjectTypeComposer<any, any>;
|
|
10
|
+
};
|
|
11
|
+
export declare function injectSystemResolvers(gql: GraphQLService, schemaComposer: SchemaComposer<GraphQLParams['contextValue']>, { CreateCollectionTypes, ReadCollectionTypes, UpdateCollectionTypes }: CollectionTypes, schema: Schema): SchemaComposer<any>;
|