From 197764194230b63a9d83a838c6540988621c5f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Cabrera=20Dur=C3=A1n?= Date: Wed, 22 Dec 2021 21:24:30 -0600 Subject: [PATCH] chore: upload and expand recursively --- lib/res.js | 182 ++++++++++++++++++++--------------------------------- 1 file changed, 68 insertions(+), 114 deletions(-) diff --git a/lib/res.js b/lib/res.js index 183cedc..cd3056e 100644 --- a/lib/res.js +++ b/lib/res.js @@ -140,7 +140,7 @@ function _fixRefs(refs, values) { }); } -function _fileInfo(baseDir, data, ex) { +function _fileInfo(baseDir, data, obj) { /* istanbul ignore else */ if (!data) { throw new Error('File data is missing'); @@ -149,12 +149,12 @@ function _fileInfo(baseDir, data, ex) { /* istanbul ignore else */ if (Array.isArray(data)) { // FIXME: additional fields on uploads - return data.map(x => _fileInfo(baseDir, x, ex)); + return data.map(x => _fileInfo(baseDir, x, obj)); } - delete ex.$upload; + delete obj.$upload; return { - ...ex, + ...obj, mtime: (data.lastModifiedDate || new Date()).toGMTString(), path: path.relative(baseDir, data.path), name: data.name, @@ -163,15 +163,24 @@ function _fileInfo(baseDir, data, ex) { }; } -function _pushUpload(key, _schema, destFile, payload, metadata, onUploadCallback) { - if (key === null) { - Object.assign(payload, metadata); - } else if (_schema.type === 'string') { - payload[key] = JSON.stringify(metadata); - } else { - payload[key] = metadata; +function _pushUpload(key, payload, metadata, destFile, onUploadCallback) { + if (Array.isArray(metadata)) { + return Promise.all(metadata.map(item => { + /* istanbul ignore else */ + if (onUploadCallback) { + return onUploadCallback({ + payload, + destFile, + field: key, + metadata: item, + }); + } + return { ...item, ...payload }; + })); } + Object.assign(payload, metadata); + /* istanbul ignore else */ if (onUploadCallback) { return onUploadCallback({ @@ -179,82 +188,44 @@ function _pushUpload(key, _schema, destFile, payload, metadata, onUploadCallback metadata, destFile, field: key, - schema: _schema, }); } + return payload; } -function _saveBase64(key, schema, payload, attachments, onUploadCallback) { - const baseDir = attachments.baseDir || process.cwd(); - - /* istanbul ignore else */ - if (_isData(payload[key])) { - const details = payload[key].match(RE_DATA)[1].split(';'); - const base64Data = payload[key].replace(RE_DATA, ''); - - const fileName = details[1] ? `_${details[1].split('name=')[1]}` : `_${details[0].replace(/\W+/g, '.')}`; - const destFile = path.join(baseDir, attachments.uploadDir || 'uploads', `${Date.now()}${fileName}`); - - // save file on disk before anything else! - fs.outputFileSync(destFile, base64Data, 'base64'); - - const metadata = { - mtime: new Date(), - path: path.relative(baseDir, destFile), - name: path.basename(destFile), - size: fs.statSync(destFile).size, - type: details[0], - }; - - return _pushUpload(key, schema, destFile, payload, metadata, onUploadCallback); - } -} - -function _saveUploads(Model, field, payload, attachments, onUploadCallback) { - const baseDir = attachments.baseDir || process.cwd(); - const schema = Model.options.$schema.properties; - const tasks = []; +function _saveBase64(key, payload, attachments, onUploadCallback) { + return Promise.resolve() + .then(() => { + const baseDir = attachments.baseDir || process.cwd(); + const details = payload[key].match(RE_DATA)[1].split(';'); + const base64Data = payload[key].replace(RE_DATA, ''); - /* istanbul ignore else */ - try { - if (payload.$upload) { - return _fileInfo(baseDir, attachments.files[payload.$upload], payload); - } - } catch (e) { - throw new Error(`Cannot retrieve ${field} '${payload.$upload}' (${e.message})`); - } + const fileName = details[1] ? `_${details[1].split('name=')[1]}` : `_${details[0].replace(/\W+/g, '.')}`; + const destFile = path.join(baseDir, attachments.uploadDir || 'uploads', `${Date.now()}${fileName}`); - if (payload[Model.name]) { - if (payload[Model.name].$upload) { - const attachment = _fileInfo(baseDir, attachments.files[payload[Model.name].$upload], payload[Model.name]); + // save file on disk before anything else! + fs.outputFileSync(destFile, base64Data, 'base64'); - tasks.push(_pushUpload(Model.name, schema, attachment.path, payload, attachment, onUploadCallback)); - } else { - Object.keys(Model.associations).forEach(assoc => { - const data = payload[Model.name][assoc]; + const metadata = { + mtime: new Date(), + path: path.relative(baseDir, destFile), + name: path.basename(destFile), + size: fs.statSync(destFile).size, + type: details[0], + }; - if (data && data.$upload && attachments.files[data.$upload]) { - const attachment = _fileInfo(baseDir, attachments.files[data.$upload], data); + return _pushUpload(key, {}, metadata, destFile, onUploadCallback); + }); +} - tasks.push(_pushUpload(assoc, schema[assoc], attachment.path, payload[Model.name], attachment, onUploadCallback)); - } - }); - } - } else { - Object.keys(Model.rawAttributes).forEach(prop => { - /* istanbul ignore else */ - if (payload[prop] - && payload[prop].$upload - && attachments.files[payload[prop].$upload] - ) { - const attachment = _fileInfo(baseDir, attachments.files[payload[prop].$upload], payload[prop]); +function _saveUpload(field, payload, attachments, onUploadCallback) { + return Promise.resolve() + .then(() => { + const baseDir = attachments.baseDir || process.cwd(); + const input = _fileInfo(baseDir, attachments.files[payload.$upload], payload); - tasks.push(_pushUpload(prop, schema[prop], attachment.path, payload, attachment, onUploadCallback)); - } + return _pushUpload(field, payload, input, input.path, onUploadCallback); }); - } - - return Promise.all(tasks); } // FIXME: too much complexity for updating related rows, just create new ones!!! @@ -264,41 +235,30 @@ function _buildTasks(references, inputData, modelName, _options, models) { after: [], }; - /* istanbul ignore else */ if (_options.attachments) { - if (inputData.$upload) { - const files = _saveUploads(models[modelName], '$upload', inputData, _options.attachments); - - delete inputData.$upload; - - tasks.before.push(() => _pushUpload(null, models[modelName].options.$schema, files.path, inputData, files, _options.upload)); - } else { - tasks.before.push(() => _saveUploads(models[modelName], null, inputData, _options.attachments, _options.upload)); - } - } - - function doUpload(schema, prop, item, _ref) { - /* istanbul ignore else */ - if (_options.attachments) { - if (item.$upload) { - const files = _saveUploads(_ref, prop, item, _options.attachments); - - delete item.$upload; + // eslint-disable-next-line wrap-iife + (function walk(obj, prop, model, parent) { + /* istanbul ignore else */ + if (!obj || typeof obj !== 'object') return obj; - if (schema.type === 'array') { - inputData[prop] = []; - (Array.isArray(files) ? files : [files]).forEach((x, key) => { - tasks.before.push(() => _pushUpload(key, schema.items || {}, x.path, inputData[prop], x, _options.upload)); - }); + /* istanbul ignore else */ + if (Array.isArray(obj)) return obj.map(x => walk(x, prop, model, parent)); + + Object.keys(obj).forEach(key => { + if (key === '$upload') { + tasks.before.push(() => _saveUpload(prop, obj, _options.attachments).then(result => { + parent[prop] = result; + })); + } else if (_isData(obj[key])) { + tasks.before.push(() => _saveBase64(key, obj, _options.attachments, _options.upload).then(result => { + obj[key] = result; + })); } else { - tasks.before.push(() => _pushUpload(prop, schema, files.path, inputData, files, _options.upload)); + obj[key] = walk(obj[key], key, model, obj); } - } else { - tasks.before.push(() => (_isData(item) - ? _saveBase64(prop, schema, inputData, _options.attachments, _options.upload) - : _saveUploads(_ref, prop, item, _options.attachments, _options.upload))); - } - } + }); + return obj; + })(inputData, null, models[modelName]); } Object.keys(inputData).forEach(prop => { @@ -314,8 +274,6 @@ function _buildTasks(references, inputData, modelName, _options, models) { const _ref = _attr.type.options.Model; const _pk = _ref.primaryKeyAttribute; - doUpload(_schema, prop, inputData[prop], _ref); - tasks.before.push(_opts => _ref.create(inputData[prop], { logging: _opts.logging }) .then(result => { inputData[prop] = _fixPkNull(result, _ref)[_pk]; @@ -338,14 +296,12 @@ function _buildTasks(references, inputData, modelName, _options, models) { const _attrs = through && models[through].rawAttributes; items.filter(Boolean).forEach(item => { - doUpload(_schema, prop, item, _ref); - /* istanbul ignore else */ if (_attrs) { Object.keys(_attrs).forEach(field => { /* istanbul ignore else */ if (_attrs[field].references && typeof item[field] === 'object') { - doUpload(_schema.items || _schema, field, item, models[through]); + // doUpload(_schema.items || _schema, field, item, models[through]); tasks.before.push(_opts => _ref.create(item[field], { logging: _opts.logging }) .then(result => { @@ -437,8 +393,6 @@ function _buildTasks(references, inputData, modelName, _options, models) { .then(x => _fixPkNull(x, _ref)); }); }); - } else if (_schema.attachment && _isData(inputData[prop])) { - return _saveBase64(prop, _schema, inputData, _options.attachments, _options.upload); } } });