mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-30 14:22:07 +03:00
6fe93f6a50
Closes #3844 - Before importing, all data is checked for incorrect UUIDs. If check fails, data is sanitized and outfitted with correct UUIDS. - Scaffolding allows for easy implementation of additional sanitization, should that be required in the future. - Test included, old tests updated.
132 lines
3.8 KiB
JavaScript
132 lines
3.8 KiB
JavaScript
var when = require('when'),
|
|
_ = require('lodash'),
|
|
validation = require('../validation'),
|
|
errors = require('../../errors'),
|
|
uuid = require('node-uuid'),
|
|
validator = require('validator'),
|
|
tables = require('../schema').tables,
|
|
validate,
|
|
handleErrors,
|
|
sanitize,
|
|
cleanError;
|
|
|
|
cleanError = function cleanError(error) {
|
|
var temp,
|
|
message,
|
|
offendingProperty,
|
|
value;
|
|
|
|
if (error.raw.message.toLowerCase().indexOf('unique') !== -1) {
|
|
// This is a unique constraint failure
|
|
if (error.raw.message.indexOf('ER_DUP_ENTRY') !== -1) {
|
|
temp = error.raw.message.split('\'');
|
|
if (temp.length === 5) {
|
|
value = temp[1];
|
|
temp = temp[3].split('_');
|
|
offendingProperty = temp.length === 3 ? temp[0] + '.' + temp[1] : error.model;
|
|
}
|
|
} else if (error.raw.message.indexOf('SQLITE_CONSTRAINT') !== -1) {
|
|
temp = error.raw.message.split('failed: ');
|
|
offendingProperty = temp.length === 2 ? temp[1] : error.model;
|
|
temp = offendingProperty.split('.');
|
|
value = temp.length === 2 ? error.data[temp[1]] : 'unknown';
|
|
}
|
|
message = 'Duplicate entry found. Multiple values of "' + value + '" found for ' + offendingProperty + '.';
|
|
}
|
|
|
|
|
|
offendingProperty = offendingProperty || error.model;
|
|
value = value || 'unknown';
|
|
message = message || error.raw.message;
|
|
|
|
return new errors.DataImportError(message, offendingProperty, value);
|
|
};
|
|
|
|
|
|
handleErrors = function handleErrors(errorList) {
|
|
var processedErrors = [];
|
|
|
|
if (!_.isArray(errorList)) {
|
|
return when.reject(errorList);
|
|
}
|
|
|
|
_.each(errorList, function (error) {
|
|
if (!error.raw) {
|
|
// These are validation errors
|
|
processedErrors.push(error);
|
|
} else if (_.isArray(error.raw)) {
|
|
processedErrors = processedErrors.concat(error.raw);
|
|
} else {
|
|
processedErrors.push(cleanError(error));
|
|
}
|
|
});
|
|
|
|
return when.reject(processedErrors);
|
|
};
|
|
|
|
sanitize = function sanitize(data) {
|
|
|
|
// Check for correct UUID and fix if neccessary
|
|
_.each(_.keys(data.data), function (tableName) {
|
|
_.each(data.data[tableName], function (importValues) {
|
|
|
|
var uuidMissing = (!importValues.uuid && tables[tableName].uuid) ? true : false,
|
|
uuidMalformed = (importValues.uuid && !validator.isUUID(importValues.uuid)) ? true : false;
|
|
|
|
if (uuidMissing || uuidMalformed) {
|
|
importValues.uuid = uuid.v4();
|
|
}
|
|
});
|
|
});
|
|
|
|
return data;
|
|
};
|
|
|
|
validate = function validate(data) {
|
|
var validateOps = [];
|
|
|
|
_.each(_.keys(data.data), function (tableName) {
|
|
_.each(data.data[tableName], function (importValues) {
|
|
validateOps.push(validation.validateSchema(tableName, importValues));
|
|
});
|
|
});
|
|
|
|
return when.settle(validateOps).then(function (descriptors) {
|
|
var errorList = [];
|
|
|
|
_.each(descriptors, function (d) {
|
|
if (d.state === 'rejected') {
|
|
errorList = errorList.concat(d.reason);
|
|
}
|
|
});
|
|
|
|
if (!_.isEmpty(errorList)) {
|
|
return when.reject(errorList);
|
|
}
|
|
|
|
return when.resolve();
|
|
});
|
|
};
|
|
|
|
module.exports = function (version, data) {
|
|
var importer;
|
|
|
|
data = sanitize(data);
|
|
|
|
return validate(data).then(function () {
|
|
try {
|
|
importer = require('./' + version);
|
|
} catch (ignore) {
|
|
// Zero effs given
|
|
}
|
|
|
|
if (!importer) {
|
|
return when.reject('No importer found');
|
|
}
|
|
|
|
return importer.importData(data);
|
|
}).catch(function (result) {
|
|
return handleErrors(result);
|
|
});
|
|
};
|