From e45d95ac10d5470e9aecb665c284e8302df8006c Mon Sep 17 00:00:00 2001 From: Joan Sanchez Date: Thu, 20 Jun 2019 07:46:30 +0200 Subject: [PATCH] upload dms files into new folder structure #1548 --- .gitignore | 1 + back/methods/dms/downloadFile.js | 25 ++-- back/methods/dms/removeFile.js | 14 +- back/methods/dms/uploadFile.js | 124 ++++++++++-------- loopback/server/boot/root.js | 10 -- loopback/server/boot/storage.js | 18 +++ .../back/methods/client-dms/removeFile.js | 9 +- 7 files changed, 100 insertions(+), 101 deletions(-) create mode 100644 loopback/server/boot/storage.js diff --git a/.gitignore b/.gitignore index 864883743..814e0cdfe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules dist/* +e2e/dms/* npm-debug.log .eslintcache datasources.*.json diff --git a/back/methods/dms/downloadFile.js b/back/methods/dms/downloadFile.js index 574ad6972..523bd39bd 100644 --- a/back/methods/dms/downloadFile.js +++ b/back/methods/dms/downloadFile.js @@ -36,40 +36,31 @@ module.exports = Self => { Self.downloadFile = async function(ctx, id) { const env = process.env.NODE_ENV; + const storageConnector = Self.app.dataSources.storage.connector; const models = Self.app.models; - const dms = await Self.findById(id, { - include: { - relation: 'dmsType', - scope: { - fields: ['path', 'readRoleFk'], - include: { - relation: 'readRole' - } - } - } - }); + const dms = await Self.findById(id); const hasReadRole = await models.DmsType.hasReadRole(ctx, dms.dmsTypeFk); if (!hasReadRole) throw new UserError(`You don't have enough privileges`); if (env && env != 'development') { - const path = `/${dms.companyFk}/${dms.dmsType().path}/${dms.file}`; + const pathHash = storageConnector.getPathHash(dms.id); file = { - path: `/var/lib/salix/dms/${path}`, contentType: 'application/octet-stream', + container: pathHash, name: dms.file }; } else { file = { - path: `${process.cwd()}/README.md`, contentType: 'text/plain', - name: `README.md` + container: 'temp', + name: `file.txt` }; } - await fs.access(file.path); - let stream = fs.createReadStream(file.path); + const stream = await models.Container.downloadStream(file.container, file.name); + return [stream, file.contentType, `filename="${file.name}"`]; }; }; diff --git a/back/methods/dms/removeFile.js b/back/methods/dms/removeFile.js index 71d9cc2c8..350bea6bc 100644 --- a/back/methods/dms/removeFile.js +++ b/back/methods/dms/removeFile.js @@ -1,5 +1,4 @@ const UserError = require('vn-loopback/util/user-error'); -const fs = require('fs-extra'); module.exports = Self => { Self.remoteMethodCtx('removeFile', { @@ -23,24 +22,13 @@ module.exports = Self => { Self.removeFile = async(ctx, id) => { const models = Self.app.models; + const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}); const dms = await models.Dms.findById(id); - const dmsType = await models.DmsType.findById(dms.dmsTypeFk); - const trashDmsType = await models.DmsType.findOne({ - where: { - code: 'trash' - } - }); const hasWriteRole = await models.DmsType.hasWriteRole(ctx, dms.dmsTypeFk); if (!hasWriteRole) throw new UserError(`You don't have enough privileges`); - const file = await models.Container.getFile(dmsType.path, dms.file); - const originPath = `${file.client.root}/${dmsType.path}/${file.name}`; - const destinationPath = `${file.client.root}/${trashDmsType.path}/${file.name}`; - - await fs.rename(originPath, destinationPath); - return dms.updateAttribute('dmsTypeFk', trashDmsType.id); }; }; diff --git a/back/methods/dms/uploadFile.js b/back/methods/dms/uploadFile.js index e137ca8ff..3091f7184 100644 --- a/back/methods/dms/uploadFile.js +++ b/back/methods/dms/uploadFile.js @@ -1,5 +1,6 @@ -const fs = require('fs-extra'); const UserError = require('vn-loopback/util/user-error'); +const fs = require('fs-extra'); +const md5 = require('md5'); module.exports = Self => { Self.remoteMethodCtx('uploadFile', { @@ -7,9 +8,6 @@ module.exports = Self => { accessType: 'WRITE', accepts: [ { - arg: 'options', - type: 'object' - }, { arg: 'warehouseId', type: 'Number', description: '' @@ -33,8 +31,7 @@ module.exports = Self => { arg: 'hasFile', type: 'Boolean', description: '' - } - ], + }], returns: { type: 'Object', root: true @@ -45,23 +42,20 @@ module.exports = Self => { } }); - Self.uploadFile = async(ctx, options) => { - const models = Self.app.models; + Self.uploadFile = async(ctx, options = {}) => { const storageConnector = Self.app.dataSources.storage.connector; - const myUserId = ctx.req.accessToken.userId; - const myWorker = await models.Worker.findOne({where: {userFk: myUserId}}); - const args = ctx.args; + const models = Self.app.models; const fileOptions = {}; + const args = ctx.args; let tx; - let myOptions = {}; if (typeof options == 'object') - Object.assign(myOptions, options); + Object.assign(options, options); - if (!myOptions.transaction) { + if (!options.transaction) { tx = await Self.beginTransaction({}); - myOptions.transaction = tx; + options.transaction = tx; } try { @@ -69,59 +63,79 @@ module.exports = Self => { if (!hasWriteRole) throw new UserError(`You don't have enough privileges`); - // Create final folder if not exists - const dmsType = await models.DmsType.findById(args.dmsTypeId); - await models.Container.getContainer(dmsType.path).catch(async err => { - if (err.code === 'ENOENT') { - await models.Container.createContainer({ - name: dmsType.path - }); - } - }); - // Upload file to temporary path - const uploaded = await models.Container.upload('temp', ctx.req, ctx.result, fileOptions); + const tempContainer = await getContainer('temp'); + const uploaded = await models.Container.upload(tempContainer.name, ctx.req, ctx.result, fileOptions); const files = Object.values(uploaded.files).map(file => { return file[0]; }); - const promises = []; + const addedDms = []; + for (const file of files) { + const newDms = await createDms(ctx, file.name, options); + const pathHash = storageConnector.getPathHash(newDms.id); + const container = await getContainer(pathHash); - files.forEach(file => { - const newDms = Self.create({ - workerFk: myWorker.id, - dmsTypeFk: args.dmsTypeId, - companyFk: args.companyId, - warehouseFk: args.warehouseId, - reference: args.reference, - description: args.description, - hasFile: args.hasFile - }, myOptions).then(newDms => { - const extension = storageConnector.getFileExtension(file.name); - const fileName = `${newDms.id}.${extension}`; + const originPath = `${tempContainer.client.root}/${tempContainer.name}/${file.name}`; + const destinationPath = `${container.client.root}/${pathHash}/${newDms.file}`; - return newDms.updateAttribute('file', fileName, myOptions); - }).then(dms => { - return models.Container.getContainer('temp').then(container => { - const originPath = `${container.client.root}/${container.name}/${file.name}`; - const destinationPath = `${container.client.root}/${dmsType.path}/${dms.file}`; + fs.rename(originPath, destinationPath); - return fs.rename(originPath, destinationPath).then(() => { - return dms; - }); - }); - }); - - promises.push(newDms); - }); - - const resolvedPromise = await Promise.all(promises); + addedDms.push(newDms); + } if (tx) await tx.commit(); - return resolvedPromise; + return addedDms; } catch (e) { if (tx) await tx.rollback(); throw e; } }; + + async function createDms(ctx, fileName, options) { + const models = Self.app.models; + const storageConnector = Self.app.dataSources.storage.connector; + const myUserId = ctx.req.accessToken.userId; + const myWorker = await models.Worker.findOne({where: {userFk: myUserId}}); + const args = ctx.args; + + const newDms = await Self.create({ + workerFk: myWorker.id, + dmsTypeFk: args.dmsTypeId, + companyFk: args.companyId, + warehouseFk: args.warehouseId, + reference: args.reference, + description: args.description, + hasFile: args.hasFile + }, options); + + const extension = storageConnector.getFileExtension(fileName); + fileName = `${newDms.id}.${extension}`; + + return newDms.updateAttribute('file', fileName, options); + } + + + /** + * Returns a container instance + * If doesn't exists creates a new one + * + * @param {String} name Container name + * @return {Object} Container instance + */ + async function getContainer(name) { + const models = Self.app.models; + let container; + try { + container = await models.Container.getContainer(name); + } catch (err) { + if (err.code === 'ENOENT') { + container = await models.Container.createContainer({ + name: name + }); + } else throw err; + } + + return container; + } }; diff --git a/loopback/server/boot/root.js b/loopback/server/boot/root.js index 7a5591571..f70b32cb0 100644 --- a/loopback/server/boot/root.js +++ b/loopback/server/boot/root.js @@ -1,5 +1,3 @@ -const uuid = require('uuid/v1'); - module.exports = function(app) { let models = app.models(); models.forEach(function(model) { @@ -33,14 +31,6 @@ module.exports = function(app) { router.get('/status', app.loopback.status()); app.use(router); - const storageConnector = app.dataSources.storage.connector; - storageConnector.getFilename = function(file) { - return `${uuid()}.${storageConnector.getFileExtension(file.name)}`; - }; - - storageConnector.getFileExtension = function(fileName) { - return fileName.split('.').pop(); - }; /* let ds = app.dataSources.auth; //ds.automigrate(function() { diff --git a/loopback/server/boot/storage.js b/loopback/server/boot/storage.js new file mode 100644 index 000000000..997bb9d3c --- /dev/null +++ b/loopback/server/boot/storage.js @@ -0,0 +1,18 @@ +const uuid = require('uuid/v1'); +const md5 = require('md5'); + +module.exports = app => { + const storageConnector = app.dataSources.storage.connector; + + storageConnector.getFilename = function(file) { + return `${uuid()}.${storageConnector.getFileExtension(file.name)}`; + }; + + storageConnector.getFileExtension = function(fileName) { + return fileName.split('.').pop(); + }; + + storageConnector.getPathHash = function(id) { + return md5(id).substring(0, 2); + }; +}; diff --git a/modules/client/back/methods/client-dms/removeFile.js b/modules/client/back/methods/client-dms/removeFile.js index 96110bc11..6cf7ccc41 100644 --- a/modules/client/back/methods/client-dms/removeFile.js +++ b/modules/client/back/methods/client-dms/removeFile.js @@ -20,14 +20,11 @@ module.exports = Self => { Self.removeFile = async(ctx, id) => { const models = Self.app.models; - const targetClientDms = await models.ClientDms.findById(id); - const targetDms = await models.Dms.findById(targetClientDms.dmsFk); - const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}); + const clientDms = await models.ClientDms.findById(id); - await models.Dms.removeFile(ctx, targetClientDms.dmsFk); - await targetClientDms.destroy(); + await models.Dms.removeFile(ctx, clientDms.dmsFk); - return targetDms.updateAttribute('dmsTypeFk', trashDmsType.id); + return clientDms.destroy(); }; };