import { IResolvers } from 'apollo-server-express' import fs from 'fs' import randombytes from 'randombytes' import { uploadDir } from './constants' import { checkPermission } from '../user/resolvers' import { saveStreamToFile, processImage, processVideo, processAudio } from './utils' export const resolvers: IResolvers = { Query: { fsFiles: async (parent, { directory }, context, info) => { checkPermission(context, 'ADMIN') const data = await fsFiles(directory) return data }, files: (parent, args, context, info) => { checkPermission(context, 'ADMIN') return context.db.query.files(args, info) }, file: (parent, args, context, info) => { checkPermission(context, 'ADMIN') return context.db.query.file(args, info) }, }, Mutation: { uploadFile: async (parent, { file, ...args }, context, info) => { checkPermission(context, 'ADMIN') const fileInfo = await uploadFile(file) return context.db.mutation.createFile( { data: { ...args, ...fileInfo, user: { connect: { id: context.req.userId } }, }, }, info ) }, updateFile: (parent, args, context, info) => { checkPermission(context, 'ADMIN') return context.db.mutation.updateFile(args, info) }, deleteFile: async (parent, { id }, context, info) => { checkPermission(context, 'ADMIN') const file = await context.db.query.file({ where: { id } }) if (!file) throw Error(`File '${id}' not found.`) console.log(file) try { await fs.promises.unlink(file.path) } catch (error) {} return context.db.mutation.deleteFile({ where: { id } }) }, }, } async function fsFiles(directory: string) { const fileList = await fs.promises.readdir(directory) return Promise.all( fileList.map(async (filename) => { const path = `${directory}/${filename}` const { size, ctime, mtime } = await fs.promises.stat(path) return { filename, path, size, ctime, mtime, } }) ) } async function uploadFile(file: any) { const { createReadStream, filename, mimetype, encoding } = await file const stream = createReadStream() const fsFilename = randombytes(16).toString('hex') const path: [string, string] = [uploadDir, fsFilename] const filePath = path.join('/') let fileDetails = { filename, mimetype, encoding, path: filePath } if (mimetype.startsWith('image/')) { const imageDetails = await processImage(stream, path) fileDetails = { ...fileDetails, ...imageDetails } } else if (mimetype.startsWith('video/')) { const videoDetails = await processVideo(stream, path) fileDetails = { ...fileDetails, ...videoDetails } } else if (mimetype.startsWith('audio/')) { const audioDetails = await processAudio(stream, path) fileDetails = { ...fileDetails, ...audioDetails } } else { await saveStreamToFile(stream, path) } const { size } = await fs.promises.stat(filePath) return { ...fileDetails, size } }