directus
273 строки · 6.6 Кб
1import { ErrorCode, InvalidPayloadError, isDirectusError } from '@directus/errors';
2import type { PrimaryKey } from '@directus/types';
3import express from 'express';
4import { assign } from 'lodash-es';
5import { respond } from '../middleware/respond.js';
6import useCollection from '../middleware/use-collection.js';
7import { validateBatch } from '../middleware/validate-batch.js';
8import { MetaService } from '../services/meta.js';
9import { VersionsService } from '../services/versions.js';
10import asyncHandler from '../utils/async-handler.js';
11import { sanitizeQuery } from '../utils/sanitize-query.js';
12
13const router = express.Router();
14
15router.use(useCollection('directus_versions'));
16
17router.post(
18'/',
19asyncHandler(async (req, res, next) => {
20const service = new VersionsService({
21accountability: req.accountability,
22schema: req.schema,
23});
24
25const savedKeys: PrimaryKey[] = [];
26
27if (Array.isArray(req.body)) {
28const keys = await service.createMany(req.body);
29savedKeys.push(...keys);
30} else {
31const primaryKey = await service.createOne(req.body);
32savedKeys.push(primaryKey);
33}
34
35try {
36if (Array.isArray(req.body)) {
37const records = await service.readMany(savedKeys, req.sanitizedQuery);
38res.locals['payload'] = { data: records };
39} else {
40const record = await service.readOne(savedKeys[0]!, req.sanitizedQuery);
41res.locals['payload'] = { data: record };
42}
43} catch (error: any) {
44if (isDirectusError(error, ErrorCode.Forbidden)) {
45return next();
46}
47
48throw error;
49}
50
51return next();
52}),
53respond,
54);
55
56const readHandler = asyncHandler(async (req, res, next) => {
57const service = new VersionsService({
58accountability: req.accountability,
59schema: req.schema,
60});
61
62const metaService = new MetaService({
63accountability: req.accountability,
64schema: req.schema,
65});
66
67let result;
68
69if (req.singleton) {
70result = await service.readSingleton(req.sanitizedQuery);
71} else if (req.body.keys) {
72result = await service.readMany(req.body.keys, req.sanitizedQuery);
73} else {
74result = await service.readByQuery(req.sanitizedQuery);
75}
76
77const meta = await metaService.getMetaForQuery(req.collection, req.sanitizedQuery);
78
79res.locals['payload'] = { data: result, meta };
80return next();
81});
82
83router.get('/', validateBatch('read'), readHandler, respond);
84router.search('/', validateBatch('read'), readHandler, respond);
85
86router.get(
87'/:pk',
88asyncHandler(async (req, res, next) => {
89const service = new VersionsService({
90accountability: req.accountability,
91schema: req.schema,
92});
93
94const record = await service.readOne(req.params['pk']!, req.sanitizedQuery);
95
96res.locals['payload'] = { data: record || null };
97return next();
98}),
99respond,
100);
101
102router.patch(
103'/',
104validateBatch('update'),
105asyncHandler(async (req, res, next) => {
106const service = new VersionsService({
107accountability: req.accountability,
108schema: req.schema,
109});
110
111let keys: PrimaryKey[] = [];
112
113if (Array.isArray(req.body)) {
114keys = await service.updateBatch(req.body);
115} else if (req.body.keys) {
116keys = await service.updateMany(req.body.keys, req.body.data);
117} else {
118const sanitizedQuery = sanitizeQuery(req.body.query, req.accountability);
119keys = await service.updateByQuery(sanitizedQuery, req.body.data);
120}
121
122try {
123const result = await service.readMany(keys, req.sanitizedQuery);
124res.locals['payload'] = { data: result || null };
125} catch (error: any) {
126if (isDirectusError(error, ErrorCode.Forbidden)) {
127return next();
128}
129
130throw error;
131}
132
133return next();
134}),
135respond,
136);
137
138router.patch(
139'/:pk',
140asyncHandler(async (req, res, next) => {
141const service = new VersionsService({
142accountability: req.accountability,
143schema: req.schema,
144});
145
146const primaryKey = await service.updateOne(req.params['pk']!, req.body);
147
148try {
149const record = await service.readOne(primaryKey, req.sanitizedQuery);
150res.locals['payload'] = { data: record || null };
151} catch (error: any) {
152if (isDirectusError(error, ErrorCode.Forbidden)) {
153return next();
154}
155
156throw error;
157}
158
159return next();
160}),
161respond,
162);
163
164router.delete(
165'/',
166validateBatch('delete'),
167asyncHandler(async (req, _res, next) => {
168const service = new VersionsService({
169accountability: req.accountability,
170schema: req.schema,
171});
172
173if (Array.isArray(req.body)) {
174await service.deleteMany(req.body);
175} else if (req.body.keys) {
176await service.deleteMany(req.body.keys);
177} else {
178const sanitizedQuery = sanitizeQuery(req.body.query, req.accountability);
179await service.deleteByQuery(sanitizedQuery);
180}
181
182return next();
183}),
184respond,
185);
186
187router.delete(
188'/:pk',
189asyncHandler(async (req, _res, next) => {
190const service = new VersionsService({
191accountability: req.accountability,
192schema: req.schema,
193});
194
195await service.deleteOne(req.params['pk']!);
196
197return next();
198}),
199respond,
200);
201
202router.get(
203'/:pk/compare',
204asyncHandler(async (req, res, next) => {
205const service = new VersionsService({
206accountability: req.accountability,
207schema: req.schema,
208});
209
210const version = await service.readOne(req.params['pk']!);
211
212const { outdated, mainHash } = await service.verifyHash(version['collection'], version['item'], version['hash']);
213
214const saves = await service.getVersionSavesById(version['id']);
215
216const current = assign({}, ...saves);
217
218const main = await service.getMainItem(version['collection'], version['item']);
219
220res.locals['payload'] = { data: { outdated, mainHash, current, main } };
221
222return next();
223}),
224respond,
225);
226
227router.post(
228'/:pk/save',
229asyncHandler(async (req, res, next) => {
230const service = new VersionsService({
231accountability: req.accountability,
232schema: req.schema,
233});
234
235const version = await service.readOne(req.params['pk']!);
236
237const mainItem = await service.getMainItem(version['collection'], version['item']);
238
239await service.save(req.params['pk']!, req.body);
240
241const saves = await service.getVersionSavesById(req.params['pk']!);
242
243const result = assign(mainItem, ...saves);
244
245res.locals['payload'] = { data: result || null };
246
247return next();
248}),
249respond,
250);
251
252router.post(
253'/:pk/promote',
254asyncHandler(async (req, res, next) => {
255if (typeof req.body.mainHash !== 'string') {
256throw new InvalidPayloadError({ reason: `"mainHash" field is required` });
257}
258
259const service = new VersionsService({
260accountability: req.accountability,
261schema: req.schema,
262});
263
264const updatedItemKey = await service.promote(req.params['pk']!, req.body.mainHash, req.body?.['fields']);
265
266res.locals['payload'] = { data: updatedItemKey || null };
267
268return next();
269}),
270respond,
271);
272
273export default router;
274