diff --git a/src/routes/files.ts b/src/routes/files.ts index 28087053c9..7cb1a7edc9 100644 --- a/src/routes/files.ts +++ b/src/routes/files.ts @@ -6,6 +6,7 @@ import validateQuery from '../middleware/validate-query'; import * as FilesService from '../services/files'; import storage from '../storage'; import { Readable } from 'stream'; +import logger from '../logger'; const router = express.Router(); @@ -15,33 +16,44 @@ router.post( const busboy = new Busboy({ headers: req.headers }); /** - * The order of the fields in multipart/form-data is important. We require that storage is set - * before the file contents itself. This allows us to set and use the correct storage adapter - * for the file upload. + * The order of the fields in multipart/form-data is important. We require that all fields + * are provided _before_ the files. This allows us to set the storage location, and create + * the row in directus_files async during the upload of the actual file. */ let disk: string; + let payload: Record = {}; busboy.on('field', (fieldname, val) => { if (fieldname === 'storage') { disk = val; } + + payload[fieldname] = val; }); busboy.on('file', async (fieldname, fileStream, filename, encoding, mimetype) => { if (!disk) { + // @todo error return busboy.emit('error', new Error('no storage provided')); } + payload = { + ...payload, + filename_disk: filename, + filename_download: filename, + type: mimetype, + }; + + fileStream.on('end', () => { + logger.info(`File ${filename} uploaded to ${disk}.`); + }); + try { - await storage.disk(disk).put(filename, fileStream as Readable); + await FilesService.createFile(fileStream, payload); } catch (err) { busboy.emit('error', err); } - - fileStream.on('end', () => { - console.log(`File ${filename} saved.`); - }); }); busboy.on('error', (error: Error) => { diff --git a/src/services/files.ts b/src/services/files.ts index 550ff3ebe0..9070f81b9b 100644 --- a/src/services/files.ts +++ b/src/services/files.ts @@ -1,10 +1,20 @@ import { Query } from '../types/query'; import * as ItemsService from './items'; +import storage from '../storage'; +import * as PayloadService from './payload'; -/** @TODO This is a little more involved ofc, circling back later */ -// export const createFile = async (data: Record, query: Query) => { -// return await ItemsService.createItem('directus_files', data, query); -// }; +export const createFile = async ( + stream: NodeJS.ReadableStream, + data: Record, + query?: Query +) => { + const payload = await PayloadService.processValues('create', 'directus_files', data); + + await ItemsService.createItem('directus_files', payload, query); + + // @todo type of stream in flydrive is wrong: https://github.com/Slynova-Org/flydrive/issues/145 + await storage.disk(data.storage).put(data.filename_disk, stream as any); +}; export const readFiles = async (query: Query) => { return await ItemsService.readItems('directus_files', query);