Skip to content

Commit

Permalink
chore: upload and expand recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
pateketrueke committed Dec 23, 2021
1 parent 7ef5b16 commit 1977641
Showing 1 changed file with 68 additions and 114 deletions.
182 changes: 68 additions & 114 deletions lib/res.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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,
Expand All @@ -163,98 +163,69 @@ 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({
payload,
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!!!
Expand All @@ -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 => {
Expand All @@ -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];
Expand All @@ -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 => {
Expand Down Expand Up @@ -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);
}
}
});
Expand Down

0 comments on commit 1977641

Please sign in to comment.