directus

Форк
0
313 строк · 7.2 Кб
1
import { useEnv } from '@directus/env';
2
import { ErrorCode, InvalidPayloadError, isDirectusError } from '@directus/errors';
3
import type { PrimaryKey } from '@directus/types';
4
import express from 'express';
5
import Joi from 'joi';
6
import { REFRESH_COOKIE_OPTIONS, SESSION_COOKIE_OPTIONS, UUID_REGEX } from '../constants.js';
7
import { respond } from '../middleware/respond.js';
8
import useCollection from '../middleware/use-collection.js';
9
import { validateBatch } from '../middleware/validate-batch.js';
10
import { SharesService } from '../services/shares.js';
11
import type { AuthenticationMode } from '../types/index.js';
12
import asyncHandler from '../utils/async-handler.js';
13
import { sanitizeQuery } from '../utils/sanitize-query.js';
14

15
const router = express.Router();
16
const env = useEnv();
17

18
router.use(useCollection('directus_shares'));
19

20
const sharedLoginSchema = Joi.object({
21
	share: Joi.string().required(),
22
	password: Joi.string(),
23
	mode: Joi.string().valid('cookie', 'json', 'session').optional(),
24
}).unknown();
25

26
router.post(
27
	'/auth',
28
	asyncHandler(async (req, res, next) => {
29
		// This doesn't use accountability, as the user isn't logged in at this point
30
		const service = new SharesService({
31
			schema: req.schema,
32
		});
33

34
		const { error } = sharedLoginSchema.validate(req.body);
35

36
		if (error) {
37
			throw new InvalidPayloadError({ reason: error.message });
38
		}
39

40
		const mode: AuthenticationMode = req.body.mode ?? 'json';
41

42
		const { accessToken, refreshToken, expires } = await service.login(req.body, {
43
			session: mode === 'session',
44
		});
45

46
		const payload = { expires } as { expires: number; access_token?: string; refresh_token?: string };
47

48
		if (mode === 'json') {
49
			payload.refresh_token = refreshToken;
50
			payload.access_token = accessToken;
51
		}
52

53
		if (mode === 'cookie') {
54
			res.cookie(env['REFRESH_TOKEN_COOKIE_NAME'] as string, refreshToken, REFRESH_COOKIE_OPTIONS);
55
			payload.access_token = accessToken;
56
		}
57

58
		if (mode === 'session') {
59
			res.cookie(env['SESSION_COOKIE_NAME'] as string, accessToken, SESSION_COOKIE_OPTIONS);
60
		}
61

62
		res.locals['payload'] = { data: payload };
63

64
		return next();
65
	}),
66
	respond,
67
);
68

69
const sharedInviteSchema = Joi.object({
70
	share: Joi.string().required(),
71
	emails: Joi.array().items(Joi.string()),
72
}).unknown();
73

74
router.post(
75
	'/invite',
76
	asyncHandler(async (req, _res, next) => {
77
		const service = new SharesService({
78
			schema: req.schema,
79
			accountability: req.accountability,
80
		});
81

82
		const { error } = sharedInviteSchema.validate(req.body);
83

84
		if (error) {
85
			throw new InvalidPayloadError({ reason: error.message });
86
		}
87

88
		await service.invite(req.body);
89

90
		return next();
91
	}),
92
	respond,
93
);
94

95
router.post(
96
	'/',
97
	asyncHandler(async (req, res, next) => {
98
		const service = new SharesService({
99
			accountability: req.accountability,
100
			schema: req.schema,
101
		});
102

103
		const savedKeys: PrimaryKey[] = [];
104

105
		if (Array.isArray(req.body)) {
106
			const keys = await service.createMany(req.body);
107
			savedKeys.push(...keys);
108
		} else {
109
			const key = await service.createOne(req.body);
110
			savedKeys.push(key);
111
		}
112

113
		try {
114
			if (Array.isArray(req.body)) {
115
				const items = await service.readMany(savedKeys, req.sanitizedQuery);
116
				res.locals['payload'] = { data: items };
117
			} else {
118
				const item = await service.readOne(savedKeys[0]!, req.sanitizedQuery);
119
				res.locals['payload'] = { data: item };
120
			}
121
		} catch (error: any) {
122
			if (isDirectusError(error, ErrorCode.Forbidden)) {
123
				return next();
124
			}
125

126
			throw error;
127
		}
128

129
		return next();
130
	}),
131
	respond,
132
);
133

134
const readHandler = asyncHandler(async (req, res, next) => {
135
	const service = new SharesService({
136
		accountability: req.accountability,
137
		schema: req.schema,
138
	});
139

140
	const records = await service.readByQuery(req.sanitizedQuery);
141

142
	res.locals['payload'] = { data: records || null };
143
	return next();
144
});
145

146
router.get('/', validateBatch('read'), readHandler, respond);
147
router.search('/', validateBatch('read'), readHandler, respond);
148

149
router.get(
150
	`/info/:pk(${UUID_REGEX})`,
151
	asyncHandler(async (req, res, next) => {
152
		const service = new SharesService({
153
			schema: req.schema,
154
		});
155

156
		const record = await service.readOne(req.params['pk']!, {
157
			fields: ['id', 'collection', 'item', 'password', 'max_uses', 'times_used', 'date_start', 'date_end'],
158
			filter: {
159
				_and: [
160
					{
161
						_or: [
162
							{
163
								date_start: {
164
									_lte: new Date().toISOString(),
165
								},
166
							},
167
							{
168
								date_start: {
169
									_null: true,
170
								},
171
							},
172
						],
173
					},
174
					{
175
						_or: [
176
							{
177
								date_end: {
178
									_gte: new Date().toISOString(),
179
								},
180
							},
181
							{
182
								date_end: {
183
									_null: true,
184
								},
185
							},
186
						],
187
					},
188
				],
189
			},
190
		});
191

192
		res.locals['payload'] = { data: record || null };
193
		return next();
194
	}),
195
	respond,
196
);
197

198
router.get(
199
	`/:pk(${UUID_REGEX})`,
200
	asyncHandler(async (req, res, next) => {
201
		const service = new SharesService({
202
			accountability: req.accountability,
203
			schema: req.schema,
204
		});
205

206
		const record = await service.readOne(req.params['pk']!, req.sanitizedQuery);
207

208
		res.locals['payload'] = { data: record || null };
209
		return next();
210
	}),
211
	respond,
212
);
213

214
router.patch(
215
	'/',
216
	validateBatch('update'),
217
	asyncHandler(async (req, res, next) => {
218
		const service = new SharesService({
219
			accountability: req.accountability,
220
			schema: req.schema,
221
		});
222

223
		let keys: PrimaryKey[] = [];
224

225
		if (Array.isArray(req.body)) {
226
			keys = await service.updateBatch(req.body);
227
		} else if (req.body.keys) {
228
			keys = await service.updateMany(req.body.keys, req.body.data);
229
		} else {
230
			const sanitizedQuery = sanitizeQuery(req.body.query, req.accountability);
231
			keys = await service.updateByQuery(sanitizedQuery, req.body.data);
232
		}
233

234
		try {
235
			const result = await service.readMany(keys, req.sanitizedQuery);
236
			res.locals['payload'] = { data: result };
237
		} catch (error: any) {
238
			if (isDirectusError(error, ErrorCode.Forbidden)) {
239
				return next();
240
			}
241

242
			throw error;
243
		}
244

245
		return next();
246
	}),
247
	respond,
248
);
249

250
router.patch(
251
	`/:pk(${UUID_REGEX})`,
252
	asyncHandler(async (req, res, next) => {
253
		const service = new SharesService({
254
			accountability: req.accountability,
255
			schema: req.schema,
256
		});
257

258
		const primaryKey = await service.updateOne(req.params['pk']!, req.body);
259

260
		try {
261
			const item = await service.readOne(primaryKey, req.sanitizedQuery);
262
			res.locals['payload'] = { data: item || null };
263
		} catch (error: any) {
264
			if (isDirectusError(error, ErrorCode.Forbidden)) {
265
				return next();
266
			}
267

268
			throw error;
269
		}
270

271
		return next();
272
	}),
273
	respond,
274
);
275

276
router.delete(
277
	'/',
278
	asyncHandler(async (req, _res, next) => {
279
		const service = new SharesService({
280
			accountability: req.accountability,
281
			schema: req.schema,
282
		});
283

284
		if (Array.isArray(req.body)) {
285
			await service.deleteMany(req.body);
286
		} else if (req.body.keys) {
287
			await service.deleteMany(req.body.keys);
288
		} else {
289
			const sanitizedQuery = sanitizeQuery(req.body.query, req.accountability);
290
			await service.deleteByQuery(sanitizedQuery);
291
		}
292

293
		return next();
294
	}),
295
	respond,
296
);
297

298
router.delete(
299
	`/:pk(${UUID_REGEX})`,
300
	asyncHandler(async (req, _res, next) => {
301
		const service = new SharesService({
302
			accountability: req.accountability,
303
			schema: req.schema,
304
		});
305

306
		await service.deleteOne(req.params['pk']!);
307

308
		return next();
309
	}),
310
	respond,
311
);
312

313
export default router;
314

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.