1
0
Fork 0
mirror of https://github.com/codex-team/codex.docs.git synced 2025-07-24 23:59:46 +02:00
codex.docs/src/controllers/transport.js
George Berezhnoy 404fb4642e
Transport controller and file model (#42)
* Transport controller and file model

* Use randomBytes intead of pseudoRandomBytes

* Cover all lines with tests

* Update code style

* Update code style

* View for image block

* Fix serving static files

* Mkdir -p for uploads dirs

* Add default secret param

* Add image Tool

* Update src/utils/objects.js

Co-Authored-By: talyguryn <vitalik7tv@yandex.ru>

* Use vars for image tool colors

* Revert var

* Remove --color-gray-border var

* Update src/controllers/transport.js

Co-Authored-By: talyguryn <vitalik7tv@yandex.ru>

* Add mp4 support for Image Tool
2019-03-11 18:44:00 +03:00

119 lines
3.2 KiB
JavaScript

const fileType = require('file-type');
const fetch = require('node-fetch');
const fs = require('fs');
const nodePath = require('path');
const Model = require('../models/file');
const { random16 } = require('../utils/crypto');
const { deepMerge } = require('../utils/objects');
const config = require('../../config');
/**
* @class Transport
* @classdesc Transport controller
*
* Allows to save files from client or fetch them by URL
*/
class Transport {
/**
* Saves file passed from client
* @param {object} multerData - file data from multer
* @param {string} multerData.originalname - original name of the file
* @param {string} multerData.filename - name of the uploaded file
* @param {string} multerData.path - path to the uploaded file
* @param {number} multerData.size - size of the uploaded file
* @param {string} multerData.mimetype - MIME type of the uploaded file
*
* @param {object} map - object that represents how should fields of File object should be mapped to response
* @return {Promise<FileData>}
*/
static async save(multerData, map) {
const { originalname: name, path, filename, size, mimetype } = multerData;
const file = new Model({ name, filename, path, size, mimetype });
await file.save();
let response = file.data;
if (map) {
response = Transport.composeResponse(file, map);
}
return response;
}
/**
* Fetches file by passed URL
* @param {string} url - URL of the file
* @param {object} map - object that represents how should fields of File object should be mapped to response
* @return {Promise<FileData>}
*/
static async fetch(url, map) {
const fetchedFile = await fetch(url);
const buffer = await fetchedFile.buffer();
const filename = await random16();
const type = fileType(buffer);
const ext = type ? type.ext : nodePath.extname(url).slice(1);
fs.writeFileSync(`${config.uploads}/${filename}.${ext}`, buffer);
const file = new Model({
name: url,
filename: `${filename}.${ext}`,
path: `${config.uploads}/${filename}.${ext}`,
size: buffer.length,
mimetype: type ? type.mime : fetchedFile.headers.get('content-type')
});
await file.save();
let response = file.data;
if (map) {
response = Transport.composeResponse(file, map);
}
return response;
}
/**
* Map fields of File object to response by provided map object
*
* @param {File} file
* @param {object} map - object that represents how should fields of File object should be mapped to response
*
*/
static composeResponse(file, map) {
const response = {};
const { data } = file;
Object.entries(map).forEach(([name, path]) => {
const fields = path.split(':');
if (fields.length > 1) {
let object = {};
let result = object;
fields.forEach((field, i) => {
if (i === fields.length - 1) {
object[field] = data[name];
return;
}
object[field] = {};
object = object[field];
});
deepMerge(response, result);
} else {
response[fields[0]] = data[name];
}
});
return response;
}
}
module.exports = Transport;