Improved error handling when upgrading content.

d6
Frode Petterson 2014-09-29 17:13:47 +02:00
parent a38a0f1253
commit 2011e856c0
1 changed files with 86 additions and 75 deletions

View File

@ -2,18 +2,18 @@ var H5PUpgrades = H5PUpgrades || {};
(function ($) {
var info, $container, librariesCache = {};
// Initialize
$(document).ready(function () {
// Get library info
info = H5PIntegration.getLibraryInfo();
// Get and reset container
$container = $('#h5p-admin-container').html('<p>' + info.message + '</p>');
// Make it possible to select version
var $version = $(getVersionSelect(info.versions)).appendTo($container);
// Add "go" button
$('<button/>', {
class: 'h5p-admin-upgrade-button',
@ -23,11 +23,11 @@ var H5PUpgrades = H5PUpgrades || {};
new ContentUpgrade($version.val());
}
}).appendTo($container);
});
});
/**
* Generate html for version select.
*
*
* @param {Object} versions
* @returns {String}
*/
@ -41,18 +41,18 @@ var H5PUpgrades = H5PUpgrades || {};
return html;
}
};
/**
* Private. Helps process each property on the given object asynchronously in serial order.
*
*
* @param {Object} obj
* @param {Function} process
* @param {Function} finished
*/
var asyncSerial = function (obj, process, finished) {
var id, isArray = obj instanceof Array;
// Keep track of each property that belongs to this object.
// Keep track of each property that belongs to this object.
if (!isArray) {
var ids = [];
for (id in obj) {
@ -61,9 +61,9 @@ var H5PUpgrades = H5PUpgrades || {};
}
}
}
var i = -1; // Keeps track of the current property
/**
* Private. Process the next property
*/
@ -71,10 +71,10 @@ var H5PUpgrades = H5PUpgrades || {};
id = isArray ? i : ids[i];
process(id, obj[id], check);
};
/**
* Private. Check if we're done or have an error.
*
*
* @param {String} err
*/
var check = function (err) {
@ -89,13 +89,13 @@ var H5PUpgrades = H5PUpgrades || {};
}
}, 0);
};
check(); // Start
};
/**
/**
* Make it easy to keep track of version details.
*
*
* @param {String} version
* @param {Number} libraryId
* @returns {_L1.Version}
@ -103,19 +103,19 @@ var H5PUpgrades = H5PUpgrades || {};
function Version(version, libraryId) {
if (libraryId !== undefined) {
version = info.versions[libraryId];
// Public
this.libraryId = libraryId;
}
var versionSplit = version.split('.', 3);
// Public
this.major = versionSplit[0];
this.minor = versionSplit[1];
/**
* Public. Custom string for this object.
*
*
* @returns {String}
*/
this.toString = function () {
@ -125,17 +125,17 @@ var H5PUpgrades = H5PUpgrades || {};
/**
* Displays a throbber in the status field.
*
*
* @param {String} msg
* @returns {_L1.Throbber}
*/
function Throbber(msg) {
var $throbber = H5PUtils.throbber(msg);
$container.html('').append($throbber);
/**
* Makes it possible to set the progress.
*
*
* @param {String} progress
*/
this.setProgress = function (progress) {
@ -145,16 +145,16 @@ var H5PUpgrades = H5PUpgrades || {};
/**
* Start a new content upgrade.
*
*
* @param {Number} libraryId
* @returns {_L1.ContentUpgrade}
*/
function ContentUpgrade(libraryId) {
var self = this;
// Get selected version
self.version = new Version(null, libraryId);
// Create throbber with loading text and progress
self.throbber = new Throbber(info.inProgress.replace('%ver', self.version));
@ -164,36 +164,36 @@ var H5PUpgrades = H5PUpgrades || {};
token: info.token
});
}
/**
* Get the next batch and start processing it.
*
*
* @param {Object} outData
*/
ContentUpgrade.prototype.nextBatch = function (outData) {
var self = this;
$.post(info.infoUrl, outData, function (inData) {
if (!(inData instanceof Object)) {
// Print errors from backend
return self.setStatus(inData);
}
}
if (inData.left === 0) {
// Nothing left to process
return self.setStatus(info.done);
}
self.left = inData.left;
self.token = inData.token;
// Start processing
self.processBatch(inData.params);
});
};
/**
* Set current status message.
*
*
* @param {String} msg
*/
ContentUpgrade.prototype.setStatus = function (msg) {
@ -202,28 +202,37 @@ var H5PUpgrades = H5PUpgrades || {};
/**
* Process the given parameters.
*
*
* @param {Object} parameters
*/
ContentUpgrade.prototype.processBatch = function (parameters) {
var self = this;
var upgraded = {}; // Track upgraded params
var current = 0; // Track progress
asyncSerial(parameters, function (id, params, next) {
// Make params possible to work with
params = JSON.parse(params);
try {
// Make params possible to work with
params = JSON.parse(params);
if (!(params instanceof Object)) {
throw true;
}
}
catch (event) {
return next(info.errorContent.replace('%id', id) + ' ' + info.errorParamsBroken);
}
// Upgrade this content.
self.upgrade(info.library.name, new Version(info.library.version), self.version, params, function (err, params) {
if (!err) {
upgraded[id] = JSON.stringify(params);
current++;
self.throbber.setProgress(Math.round((info.total - self.left + current) / (info.total / 100)) + ' %');
if (err) {
return next(info.errorContent.replace('%id', id) + ' ' + err);
}
next(err);
upgraded[id] = JSON.stringify(params);
current++;
self.throbber.setProgress(Math.round((info.total - self.left + current) / (info.total / 100)) + ' %');
next();
});
}, function (err) {
@ -240,10 +249,10 @@ var H5PUpgrades = H5PUpgrades || {};
});
});
};
/**
* Upgade the given content.
*
*
* @param {String} name
* @param {Version} oldVersion
* @param {Version} newVersion
@ -253,19 +262,19 @@ var H5PUpgrades = H5PUpgrades || {};
*/
ContentUpgrade.prototype.upgrade = function (name, oldVersion, newVersion, params, next) {
var self = this;
// Load library details and upgrade routines
self.loadLibrary(name, newVersion, function (err, library) {
if (err) {
return next(err);
}
// Run upgrade routines on params
self.processParams(library, oldVersion, newVersion, params, function (err, params) {
if (err) {
return next(err);
}
// Check if any of the sub-libraries need upgrading
asyncSerial(library.semantics, function (index, field, next) {
self.processField(field, params[field.name], function (err, upgradedParams) {
@ -280,24 +289,24 @@ var H5PUpgrades = H5PUpgrades || {};
});
});
};
/**
* Load library data needed for content upgrade.
*
*
* @param {String} name
* @param {Version} version
* @param {Function} next
*/
ContentUpgrade.prototype.loadLibrary = function (name, version, next) {
var self = this;
var key = name + '/' + version.major + '/' + version.minor;
if (librariesCache[key] !== undefined) {
// Library has been loaded before. Return cache.
next(null, librariesCache[key]);
return;
}
$.ajax({
dataType: 'json',
cache: true,
@ -306,7 +315,7 @@ var H5PUpgrades = H5PUpgrades || {};
next(info.errorData.replace('%lib', name + ' ' + version));
}).done(function (library) {
librariesCache[key] = library;
if (library.upgradesScript) {
self.loadScript(library.upgradesScript, function (err) {
if (err) {
@ -320,10 +329,10 @@ var H5PUpgrades = H5PUpgrades || {};
}
});
};
/**
* Load script with upgrade hooks.
*
*
* @param {String} url
* @param {Function} next
*/
@ -338,10 +347,10 @@ var H5PUpgrades = H5PUpgrades || {};
next();
});
};
/**
* Run upgrade hooks on params.
*
*
* @param {Object} library
* @param {Version} oldVersion
* @param {Version} newVersion
@ -354,7 +363,7 @@ var H5PUpgrades = H5PUpgrades || {};
// Upgrades script should be loaded so the upgrades should be here.
return next(info.errorScript.replace('%lib', library.name + ' ' + newVersion));
}
// No upgrades script. Move on
return next(null, params);
}
@ -362,7 +371,7 @@ var H5PUpgrades = H5PUpgrades || {};
// Run upgrade hooks. Start by going through major versions
asyncSerial(H5PUpgrades[library.name], function (major, minors, nextMajor) {
if (major < oldVersion.major || major > newVersion.major) {
// Older than the current version or newer than the selected
// Older than the current version or newer than the selected
nextMajor();
}
else {
@ -374,14 +383,16 @@ var H5PUpgrades = H5PUpgrades || {};
}
else {
// We found an upgrade hook, run it
if (upgrade.contentUpgrade !== undefined && typeof upgrade.contentUpgrade === 'function') {
upgrade.contentUpgrade(params, function (err, upgradedParams) {
var unnecessaryWrapper = (upgrade.contentUpgrade !== undefined ? upgrade.contentUpgrade : upgrade);
try {
unnecessaryWrapper(params, function (err, upgradedParams) {
params = upgradedParams;
nextMinor(err);
});
}
else {
nextMinor(info.errorScript.replace('%lib', library.name + ' ' + newVersion));
catch (err) {
next(err);
}
}
}, nextMajor);
@ -390,27 +401,27 @@ var H5PUpgrades = H5PUpgrades || {};
next(err, params);
});
};
/**
* Process parameter fields to find and upgrade sub-libraries.
*
*
* @param {Object} field
* @param {Object} params
* @param {Function} next
*/
ContentUpgrade.prototype.processField = function (field, params, next) {
var self = this;
if (params === undefined) {
return next();
}
switch (field.type) {
case 'library':
if (params.library === undefined || params.params === undefined) {
return next();
}
// Look for available upgrades
var usedLib = params.library.split(' ', 2);
for (var i = 0; i < field.options.length; i++) {
@ -419,14 +430,14 @@ var H5PUpgrades = H5PUpgrades || {};
if (availableLib[1] === usedLib[1]) {
return next(); // Same version
}
// We have different versions
var usedVer = new Version(usedLib[1]);
var availableVer = new Version(availableLib[1]);
if (usedVer.major > availableVer.major || (usedVer.major === availableVer.major && usedVer.minor >= availableVer.minor)) {
return next(); // Larger or same version that's available
}
// A newer version is available, upgrade params
return self.upgrade(availableLib[0], usedVer, availableVer, params.params, function (err, upgraded) {
if (!err) {
@ -484,4 +495,4 @@ var H5PUpgrades = H5PUpgrades || {};
}
};
})(H5P.jQuery);
})(H5P.jQuery);