mirror of
https://github.com/directus/directus.git
synced 2026-01-30 00:37:55 -05:00
Allow read processing + move write processing to items service
This commit is contained in:
@@ -5,7 +5,6 @@ import validateQuery from '../middleware/validate-query';
|
||||
import useCollection from '../middleware/use-collection';
|
||||
import * as FoldersService from '../services/folders';
|
||||
import * as ActivityService from '../services/activity';
|
||||
import * as PayloadService from '../services/payload';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -13,8 +12,7 @@ router.post(
|
||||
'/',
|
||||
useCollection('directus_folders'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const payload = await PayloadService.processValues('create', req.collection, req.body);
|
||||
const record = await FoldersService.createFolder(payload, req.sanitizedQuery);
|
||||
const record = await FoldersService.createFolder(req.body, req.sanitizedQuery);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
@@ -55,11 +53,9 @@ router.patch(
|
||||
'/:pk',
|
||||
useCollection('directus_folders'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const payload = await PayloadService.processValues('create', req.collection, req.body);
|
||||
|
||||
const record = await FoldersService.updateFolder(
|
||||
req.params.pk,
|
||||
payload,
|
||||
req.body,
|
||||
req.sanitizedQuery
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import validateCollection from '../middleware/validate-collection';
|
||||
import validateSingleton from '../middleware/validate-singleton';
|
||||
import validateQuery from '../middleware/validate-query';
|
||||
import * as MetaService from '../services/meta';
|
||||
import * as PayloadService from '../services/payload';
|
||||
import * as ActivityService from '../services/activity';
|
||||
|
||||
const router = express.Router();
|
||||
@@ -16,8 +15,7 @@ router.post(
|
||||
validateCollection,
|
||||
validateSingleton,
|
||||
asyncHandler(async (req, res) => {
|
||||
const payload = await PayloadService.processValues('create', req.collection, req.body);
|
||||
const item = await createItem(req.params.collection, payload);
|
||||
const item = await createItem(req.params.collection, req.body);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.CREATE,
|
||||
@@ -67,8 +65,7 @@ router.patch(
|
||||
'/:collection/:pk',
|
||||
validateCollection,
|
||||
asyncHandler(async (req, res) => {
|
||||
const payload = await PayloadService.processValues('update', req.collection, req.body);
|
||||
const item = await updateItem(req.params.collection, req.params.pk, payload);
|
||||
const item = await updateItem(req.params.collection, req.params.pk, req.body);
|
||||
|
||||
ActivityService.createActivity({
|
||||
action: ActivityService.Action.UPDATE,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
import storage from '../storage';
|
||||
import * as PayloadService from './payload';
|
||||
import database from '../database';
|
||||
import logger from '../logger';
|
||||
import sharp from 'sharp';
|
||||
@@ -9,14 +8,19 @@ import { parse as parseICC } from 'icc';
|
||||
import parseEXIF from 'exif-reader';
|
||||
import parseIPTC from '../utils/parse-iptc';
|
||||
import path from 'path';
|
||||
import { SYSTEM_ASSET_WHITELIST } from '../constants';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const createFile = async (
|
||||
data: Record<string, any>,
|
||||
stream: NodeJS.ReadableStream,
|
||||
query?: Query
|
||||
) => {
|
||||
const payload = await PayloadService.processValues('create', 'directus_files', data);
|
||||
const id = uuidv4();
|
||||
|
||||
const payload: Record<string, any> = {
|
||||
...data,
|
||||
id,
|
||||
};
|
||||
|
||||
payload.filename_disk = payload.id + path.extname(payload.filename_disk);
|
||||
|
||||
@@ -55,29 +59,7 @@ export const readFiles = async (query: Query) => {
|
||||
};
|
||||
|
||||
export const readFile = async (pk: string | number, query: Query) => {
|
||||
const file = await ItemsService.readItem('directus_files', pk, query);
|
||||
|
||||
const { asset_allowlist: assetAllowlist } =
|
||||
(await database.select('asset_allowlist').from('directus_settings').first()) || {};
|
||||
|
||||
const assetSizes = [...SYSTEM_ASSET_WHITELIST, ...(assetAllowlist || [])];
|
||||
|
||||
file.links = {
|
||||
asset_url: new URL(`/assets/${file.id}`, process.env.PUBLIC_URL),
|
||||
/** @TODO confirm is public url is set before returning */
|
||||
original_url: new URL(
|
||||
file.filename_disk,
|
||||
process.env[`STORAGE_${file.storage.toUpperCase()}_PUBLIC_URL`]
|
||||
),
|
||||
thumbnails: assetSizes.map((size) => {
|
||||
return {
|
||||
...size,
|
||||
url: new URL(`/assets/${file.id}?key=${size.key}`, process.env.PUBLIC_URL),
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
return file;
|
||||
return await ItemsService.readItem('directus_files', pk, query);
|
||||
};
|
||||
|
||||
// @todo Add query support
|
||||
@@ -87,8 +69,6 @@ export const updateFile = async (
|
||||
stream?: NodeJS.ReadableStream,
|
||||
query?: Query
|
||||
) => {
|
||||
const payload = await PayloadService.processValues('update', 'directus_files', data);
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* Handle changes in storage adapter -> going from local to S3 needs to delete from one, upload to the other
|
||||
@@ -110,7 +90,7 @@ export const updateFile = async (
|
||||
await storage.disk(file.storage).put(file.filename_disk, stream as any);
|
||||
}
|
||||
|
||||
return await ItemsService.updateItem('directus_files', pk, payload, query);
|
||||
return await ItemsService.updateItem('directus_files', pk, data, query);
|
||||
};
|
||||
|
||||
export const deleteFile = async (pk: string | number) => {
|
||||
|
||||
@@ -2,14 +2,16 @@ import database, { schemaInspector } from '../database';
|
||||
import { Query } from '../types/query';
|
||||
import runAST from '../database/run-ast';
|
||||
import getAST from '../utils/get-ast';
|
||||
import * as PayloadService from './payload';
|
||||
|
||||
export const createItem = async (
|
||||
collection: string,
|
||||
data: Record<string, any>,
|
||||
query: Query = {}
|
||||
) => {
|
||||
const payload = await PayloadService.processValues('create', collection, data);
|
||||
const primaryKeyField = await schemaInspector.primary(collection);
|
||||
const result = await database(collection).insert(data).returning(primaryKeyField);
|
||||
const result = await database(collection).insert(payload).returning(primaryKeyField);
|
||||
return readItem(collection, result[0], query);
|
||||
};
|
||||
|
||||
@@ -19,7 +21,7 @@ export const readItems = async <T = Record<string, any>>(
|
||||
): Promise<T[]> => {
|
||||
const ast = await getAST(collection, query);
|
||||
const records = await runAST(ast);
|
||||
return records;
|
||||
return await PayloadService.processValues('read', collection, records);
|
||||
};
|
||||
|
||||
export const readItem = async <T = any>(
|
||||
@@ -43,7 +45,7 @@ export const readItem = async <T = any>(
|
||||
|
||||
const ast = await getAST(collection, query);
|
||||
const records = await runAST(ast);
|
||||
return records[0];
|
||||
return await PayloadService.processValues('read', collection, records[0]);
|
||||
};
|
||||
|
||||
export const updateItem = async (
|
||||
@@ -52,9 +54,10 @@ export const updateItem = async (
|
||||
data: Record<string, any>,
|
||||
query: Query = {}
|
||||
) => {
|
||||
const payload = await PayloadService.processValues('create', collection, data);
|
||||
const primaryKeyField = await schemaInspector.primary(collection);
|
||||
const result = await database(collection)
|
||||
.update(data)
|
||||
.update(payload)
|
||||
.where({ [primaryKeyField]: pk })
|
||||
.returning('id');
|
||||
return readItem(collection, result[0], query);
|
||||
|
||||
@@ -9,6 +9,8 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import database from '../database';
|
||||
import { clone } from 'lodash';
|
||||
|
||||
type Operation = 'create' | 'read' | 'update';
|
||||
|
||||
/**
|
||||
* Process and update all the special fields in the given payload
|
||||
*
|
||||
@@ -18,11 +20,15 @@ import { clone } from 'lodash';
|
||||
* @returns The updated payload
|
||||
*/
|
||||
export const processValues = async (
|
||||
operation: 'create' | 'update',
|
||||
operation: Operation,
|
||||
collection: string,
|
||||
payload: Record<string, any>
|
||||
payload: Record<string, any> | Record<string, any>[]
|
||||
) => {
|
||||
const processedPayload = clone(payload);
|
||||
let processedPayload = clone(payload);
|
||||
|
||||
if (Array.isArray(payload) === false) {
|
||||
processedPayload = [processedPayload];
|
||||
}
|
||||
|
||||
const specialFieldsInCollection = await database
|
||||
.select('field', 'special')
|
||||
@@ -30,8 +36,19 @@ export const processValues = async (
|
||||
.where({ collection: collection })
|
||||
.whereNotNull('special');
|
||||
|
||||
for (const field of specialFieldsInCollection) {
|
||||
processedPayload[field.field] = await processField(field, processedPayload, operation);
|
||||
await Promise.all(
|
||||
processedPayload.map(async (record: any) => {
|
||||
await Promise.all(
|
||||
specialFieldsInCollection.map(async (field) => {
|
||||
record[field.field] = await processField(field, processedPayload, operation);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
// Return the payload in it's original format
|
||||
if (Array.isArray(payload) === false) {
|
||||
return processedPayload[0];
|
||||
}
|
||||
|
||||
return processedPayload;
|
||||
@@ -40,24 +57,47 @@ export const processValues = async (
|
||||
async function processField(
|
||||
field: Pick<System, 'field' | 'special'>,
|
||||
payload: Record<string, any>,
|
||||
operation: 'create' | 'update'
|
||||
operation: Operation
|
||||
) {
|
||||
switch (field.special) {
|
||||
case 'hash':
|
||||
return await genHash(payload[field.field]);
|
||||
return await genHash(operation, payload[field.field]);
|
||||
case 'uuid':
|
||||
return await genUUID(operation);
|
||||
return await genUUID(operation, payload[field.field]);
|
||||
case 'file-links':
|
||||
return await genFileLinks(operation, payload[field.field]);
|
||||
default:
|
||||
return payload[field.field];
|
||||
}
|
||||
}
|
||||
|
||||
async function genHash(value?: string | number) {
|
||||
/**
|
||||
* @note The following functions can be called _a lot_. Make sure to utilize some form of caching
|
||||
* if you have to rely on heavy operations
|
||||
*/
|
||||
|
||||
async function genHash(operation: Operation, value?: any) {
|
||||
if (!value) return;
|
||||
|
||||
return await argon2.hash(String(value));
|
||||
if (operation === 'create' || operation === 'update') {
|
||||
return await argon2.hash(String(value));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
async function genUUID(operation: 'create' | 'update') {
|
||||
if (operation === 'create') {
|
||||
async function genUUID(operation: Operation, value?: any) {
|
||||
if (operation === 'create' && !value) {
|
||||
return uuidv4();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
async function genFileLinks(operation: Operation, value?: any) {
|
||||
if (operation === 'read') {
|
||||
return 'test';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@ import jwt from 'jsonwebtoken';
|
||||
import { sendInviteMail } from '../mail';
|
||||
import database from '../database';
|
||||
import argon2 from 'argon2';
|
||||
import * as PayloadService from '../services/payload';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
|
||||
export const createUser = async (data: Record<string, any>, query?: Query) => {
|
||||
const payload = await PayloadService.processValues('create', 'directus_users', data);
|
||||
return await ItemsService.createItem('directus_users', payload, query);
|
||||
return await ItemsService.createItem('directus_users', data, query);
|
||||
};
|
||||
|
||||
export const readUsers = async (query?: Query) => {
|
||||
@@ -35,12 +33,7 @@ export const deleteUser = async (pk: string | number) => {
|
||||
};
|
||||
|
||||
export const inviteUser = async (email: string, role: string) => {
|
||||
const userPayload = await PayloadService.processValues('create', 'directus_users', {
|
||||
email,
|
||||
role,
|
||||
status: 'invited',
|
||||
});
|
||||
await createUser(userPayload);
|
||||
await createUser({ email, role, status: 'invited' });
|
||||
|
||||
const payload = { email };
|
||||
const token = jwt.sign(payload, process.env.SECRET, { expiresIn: '7d' });
|
||||
|
||||
Reference in New Issue
Block a user