const fs = require('fs'); const path = require('path'); const util = require('util'); const stream = require('stream'); const { v4: uuid } = require('uuid'); const sharp = require('sharp'); const Errors = { USER_NOT_FOUND: { userNotFound: 'User not found', }, }; const pipeline = util.promisify(stream.pipeline); const createReceiver = () => { const receiver = stream.Writable({ objectMode: true }); let firstFileHandled = false; // eslint-disable-next-line no-underscore-dangle receiver._write = async (file, receiverEncoding, done) => { if (firstFileHandled) { file.pipe( new stream.Writable({ write(chunk, streamEncoding, callback) { callback(); }, }), ); return done(); } firstFileHandled = true; const resize = sharp().resize(100, 100).jpeg(); const transform = new stream.Transform({ transform(chunk, streamEncoding, callback) { callback(null, chunk); }, }); try { await pipeline(file, resize, transform); file.fd = `${uuid()}.jpg`; // eslint-disable-line no-param-reassign await pipeline( transform, fs.createWriteStream(path.join(sails.config.custom.uploadsPath, file.fd)), ); return done(); } catch (error) { return done(error); } }; return receiver; }; module.exports = { inputs: { id: { type: 'string', regex: /^[0-9]+$/, required: true, }, }, exits: { userNotFound: { responseType: 'notFound', }, uploadError: { responseType: 'unprocessableEntity', }, }, async fn(inputs, exits) { const { currentUser } = this.req; let user; if (currentUser.isAdmin) { user = await sails.helpers.getUser(inputs.id); if (!user) { throw Errors.USER_NOT_FOUND; } } else if (inputs.id !== currentUser.id) { throw Errors.USER_NOT_FOUND; // Forbidden } else { user = currentUser; } this.req.file('file').upload(createReceiver(), async (error, files) => { if (error) { return exits.uploadError(error.message); } if (files.length === 0) { return exits.uploadError('No file was uploaded'); } user = await sails.helpers.updateUser( user, { avatar: files[0].fd, }, this.req, ); if (!user) { throw Errors.USER_NOT_FOUND; } return exits.success({ item: user.toJSON().avatar, }); }); }, };