Merge branch 'content-upgrade-on-upload'
commit
aa723bcb40
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class H5PSaveContentOutdatedLibraryException extends Exception { }
|
|
@ -458,6 +458,24 @@ class H5PDefaultStorage implements \H5PFileStorage {
|
||||||
return file_exists($filePath);
|
return file_exists($filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if upgrades script exist for library.
|
||||||
|
*
|
||||||
|
* @param string $machineName
|
||||||
|
* @param int $majorVersion
|
||||||
|
* @param int $minorVersion
|
||||||
|
* @return string Relative path
|
||||||
|
*/
|
||||||
|
public function getUpgradeScript($machineName, $majorVersion, $minorVersion) {
|
||||||
|
$upgrades = "/libraries/{$machineName}-{$majorVersion}.{$minorVersion}/upgrades.js";
|
||||||
|
if (file_exists($this->path . $upgrades)) {
|
||||||
|
return $upgrades;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursive function for copying directories.
|
* Recursive function for copying directories.
|
||||||
*
|
*
|
||||||
|
|
|
@ -199,4 +199,14 @@ interface H5PFileStorage {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function hasPresave($libraryName, $developmentPath = null);
|
public function hasPresave($libraryName, $developmentPath = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if upgrades script exist for library.
|
||||||
|
*
|
||||||
|
* @param string $machineName
|
||||||
|
* @param int $majorVersion
|
||||||
|
* @param int $minorVersion
|
||||||
|
* @return string Relative path
|
||||||
|
*/
|
||||||
|
public function getUpgradeScript($machineName, $majorVersion, $minorVersion);
|
||||||
}
|
}
|
||||||
|
|
|
@ -537,9 +537,10 @@ interface H5PFrameworkInterface {
|
||||||
* Get number of contents using library as main library.
|
* Get number of contents using library as main library.
|
||||||
*
|
*
|
||||||
* @param int $libraryId
|
* @param int $libraryId
|
||||||
|
* @param array $skip
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getNumContent($libraryId);
|
public function getNumContent($libraryId, $skip = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if content slug is used.
|
* Determines if content slug is used.
|
||||||
|
@ -614,6 +615,14 @@ interface H5PFrameworkInterface {
|
||||||
* containing the new content type cache that should replace the old one.
|
* containing the new content type cache that should replace the old one.
|
||||||
*/
|
*/
|
||||||
public function replaceContentTypeCache($contentTypeCache);
|
public function replaceContentTypeCache($contentTypeCache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given library has a higher version.
|
||||||
|
*
|
||||||
|
* @param array $library
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function libraryHasUpgrade($library);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -919,11 +928,27 @@ class H5PValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($missingLibraries)) {
|
if (!empty($missingLibraries)) {
|
||||||
foreach ($missingLibraries as $libString => $library) {
|
// We still have missing libraries, check if our main library has an upgrade (BUT only if we has content)
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Missing required library @library', array('@library' => $libString)), 'missing-required-library');
|
$mainDependency = NULL;
|
||||||
|
if (!$skipContent) {
|
||||||
|
foreach ($mainH5PData['preloadedDependencies'] as $dep) {
|
||||||
|
if ($dep['machineName'] === $mainH5PData['mainLibrary']) {
|
||||||
|
$mainDependency = $dep;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!$this->h5pC->mayUpdateLibraries()) {
|
|
||||||
$this->h5pF->setInfoMessage($this->h5pF->t("Note that the libraries may exist in the file you uploaded, but you're not allowed to upload new libraries. Contact the site administrator about this."));
|
if ($skipContent || !$mainDependency || !$this->h5pF->libraryHasUpgrade(array(
|
||||||
|
'machineName' => $mainDependency['mainLibrary'],
|
||||||
|
'majorVersion' => $mainDependency['majorVersion'],
|
||||||
|
'minorVersion' => $mainDependency['minorVersion']
|
||||||
|
))) {
|
||||||
|
foreach ($missingLibraries as $libString => $library) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('Missing required library @library', array('@library' => $libString)), 'missing-required-library');
|
||||||
|
}
|
||||||
|
if (!$this->h5pC->mayUpdateLibraries()) {
|
||||||
|
$this->h5pF->setInfoMessage($this->h5pF->t("Note that the libraries may exist in the file you uploaded, but you're not allowed to upload new libraries. Contact the site administrator about this."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$valid = empty($missingLibraries) && $valid;
|
$valid = empty($missingLibraries) && $valid;
|
||||||
|
@ -1394,15 +1419,23 @@ class H5PStorage {
|
||||||
if (isset($options['disable'])) {
|
if (isset($options['disable'])) {
|
||||||
$content['disable'] = $options['disable'];
|
$content['disable'] = $options['disable'];
|
||||||
}
|
}
|
||||||
$content['id'] = $this->h5pC->saveContent($content, $contentMainId);
|
|
||||||
$this->contentId = $content['id'];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Store content in database
|
||||||
|
$content['id'] = $this->h5pC->saveContent($content, $contentMainId);
|
||||||
|
$this->contentId = $content['id'];
|
||||||
|
|
||||||
// Save content folder contents
|
// Save content folder contents
|
||||||
$this->h5pC->fs->saveContent($current_path, $content);
|
$this->h5pC->fs->saveContent($current_path, $content);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
$this->h5pF->setErrorMessage($e->getMessage(), 'save-content-failed');
|
if ($e instanceof H5PSaveContentOutdatedLibraryException) {
|
||||||
|
$message = $this->h5pF->t("You're trying to upload content of an older version of H5P. Please upgrade the content on the server it originated from and try to upload again or turn on the H5P Hub to have this server upgrade it for your automaticall.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
$this->h5pF->setErrorMessage($message, 'save-content-failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove temp content folder
|
// Remove temp content folder
|
||||||
|
@ -1922,8 +1955,6 @@ class H5PCore {
|
||||||
$this->relativePathRegExp = '/^((\.\.\/){1,2})(.*content\/)?(\d+|editor)\/(.+)$/';
|
$this->relativePathRegExp = '/^((\.\.\/){1,2})(.*content\/)?(\d+|editor)\/(.+)$/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save content and clear cache.
|
* Save content and clear cache.
|
||||||
*
|
*
|
||||||
|
@ -1932,6 +1963,13 @@ class H5PCore {
|
||||||
* @return int Content ID
|
* @return int Content ID
|
||||||
*/
|
*/
|
||||||
public function saveContent($content, $contentMainId = NULL) {
|
public function saveContent($content, $contentMainId = NULL) {
|
||||||
|
|
||||||
|
// Check that this is the latest version of the content type we have
|
||||||
|
if ($this->h5pF->libraryHasUpgrade($content['library'])) {
|
||||||
|
// We do not allow storing old content due to security concerns
|
||||||
|
throw new \H5PSaveContentOutdatedLibraryException($this->h5pF->t('Something unexpected happened. We were unable to save this content.'));
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($content['id'])) {
|
if (isset($content['id'])) {
|
||||||
$this->h5pF->updateContent($content, $contentMainId);
|
$this->h5pF->updateContent($content, $contentMainId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
self.loadLibrary = loadLibrary;
|
self.loadLibrary = loadLibrary;
|
||||||
self.upgrade(name, oldVersion, newVersion, params.params, params.metadata, function (err, upgradedParams, upgradedMetadata) {
|
self.upgrade(name, oldVersion, newVersion, params.params, params.metadata, function (err, upgradedParams, upgradedMetadata) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
err.id = id;
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +54,12 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
if (library.semantics === null) {
|
||||||
|
return done({
|
||||||
|
type: 'libraryMissing',
|
||||||
|
library: library.name + ' ' + library.version.major + '.' + library.version.minor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Run upgrade routines on params
|
// Run upgrade routines on params
|
||||||
self.processParams(library, oldVersion, newVersion, params, metadata, function (err, params, metadata) {
|
self.processParams(library, oldVersion, newVersion, params, metadata, function (err, params, metadata) {
|
||||||
|
@ -176,7 +183,11 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
var usedVer = new Version(usedLib[1]);
|
var usedVer = new Version(usedLib[1]);
|
||||||
var availableVer = new Version(availableLib[1]);
|
var availableVer = new Version(availableLib[1]);
|
||||||
if (usedVer.major > availableVer.major || (usedVer.major === availableVer.major && usedVer.minor >= availableVer.minor)) {
|
if (usedVer.major > availableVer.major || (usedVer.major === availableVer.major && usedVer.minor >= availableVer.minor)) {
|
||||||
return done(); // Larger or same version that's available
|
return done({
|
||||||
|
type: 'errorTooHighVersion',
|
||||||
|
used: usedLib[0] + ' ' + usedVer,
|
||||||
|
supported: availableLib[0] + ' ' + availableVer
|
||||||
|
}); // Larger or same version that's available
|
||||||
}
|
}
|
||||||
|
|
||||||
// A newer version is available, upgrade params
|
// A newer version is available, upgrade params
|
||||||
|
@ -192,7 +203,12 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done();
|
|
||||||
|
// Content type was not supporte by the higher version
|
||||||
|
done({
|
||||||
|
type: 'errorNotSupported',
|
||||||
|
used: usedLib[0] + ' ' + usedVer
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'group':
|
case 'group':
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* global H5PAdminIntegration H5PUtils */
|
/* global H5PAdminIntegration H5PUtils */
|
||||||
|
|
||||||
(function ($, Version) {
|
(function ($, Version) {
|
||||||
var info, $container, librariesCache = {}, scriptsCache = {};
|
var info, $log, $container, librariesCache = {}, scriptsCache = {};
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
@ -9,7 +9,9 @@
|
||||||
info = H5PAdminIntegration.libraryInfo;
|
info = H5PAdminIntegration.libraryInfo;
|
||||||
|
|
||||||
// Get and reset container
|
// Get and reset container
|
||||||
$container = $('#h5p-admin-container').html('<p>' + info.message + '</p>');
|
const $wrapper = $('#h5p-admin-container').html('');
|
||||||
|
$log = $('<ul class="content-upgrade-log"></ul>').appendTo($wrapper);
|
||||||
|
$container = $('<div><p>' + info.message + '</p></div>').appendTo($wrapper);
|
||||||
|
|
||||||
// Make it possible to select version
|
// Make it possible to select version
|
||||||
var $version = $(getVersionSelect(info.versions)).appendTo($container);
|
var $version = $(getVersionSelect(info.versions)).appendTo($container);
|
||||||
|
@ -120,9 +122,7 @@
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error: function (error) {
|
||||||
self.printError(error.err);
|
self.printError(error.err);
|
||||||
|
self.workDone(error.id, null, this);
|
||||||
// Stop everything
|
|
||||||
self.terminate();
|
|
||||||
},
|
},
|
||||||
loadLibrary: function (details) {
|
loadLibrary: function (details) {
|
||||||
var worker = this;
|
var worker = this;
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
self.token = inData.token;
|
self.token = inData.token;
|
||||||
|
|
||||||
// Start processing
|
// Start processing
|
||||||
self.processBatch(inData.params);
|
self.processBatch(inData.params, inData.skipped);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -202,11 +202,12 @@
|
||||||
*
|
*
|
||||||
* @param {Object} parameters
|
* @param {Object} parameters
|
||||||
*/
|
*/
|
||||||
ContentUpgrade.prototype.processBatch = function (parameters) {
|
ContentUpgrade.prototype.processBatch = function (parameters, skipped) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Track upgraded params
|
// Track upgraded params
|
||||||
self.upgraded = {};
|
self.upgraded = {};
|
||||||
|
self.skipped = skipped;
|
||||||
|
|
||||||
// Track current batch
|
// Track current batch
|
||||||
self.parameters = parameters;
|
self.parameters = parameters;
|
||||||
|
@ -276,7 +277,7 @@
|
||||||
}, function done(err, result) {
|
}, function done(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
self.printError(err);
|
self.printError(err);
|
||||||
return ;
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.workDone(id, result);
|
self.workDone(id, result);
|
||||||
|
@ -291,7 +292,12 @@
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.working--;
|
self.working--;
|
||||||
self.upgraded[id] = result;
|
if (result === null) {
|
||||||
|
self.skipped.push(id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.upgraded[id] = result;
|
||||||
|
}
|
||||||
|
|
||||||
// Update progress message
|
// Update progress message
|
||||||
self.throbber.setProgress(Math.round((info.total - self.left + self.current) / (info.total / 100)) + ' %');
|
self.throbber.setProgress(Math.round((info.total - self.left + self.current) / (info.total / 100)) + ' %');
|
||||||
|
@ -302,6 +308,7 @@
|
||||||
self.nextBatch({
|
self.nextBatch({
|
||||||
libraryId: self.version.libraryId,
|
libraryId: self.version.libraryId,
|
||||||
token: self.token,
|
token: self.token,
|
||||||
|
skipped: JSON.stringify(self.skipped),
|
||||||
params: JSON.stringify(self.upgraded)
|
params: JSON.stringify(self.upgraded)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -410,14 +417,29 @@
|
||||||
ContentUpgrade.prototype.printError = function (error) {
|
ContentUpgrade.prototype.printError = function (error) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (error.type === 'errorParamsBroken') {
|
switch (error.type) {
|
||||||
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorParamsBroken;
|
case 'errorParamsBroken':
|
||||||
}
|
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorParamsBroken;
|
||||||
else if (error.type === 'scriptMissing') {
|
break;
|
||||||
error = info.errorScript.replace('%lib', error.library);
|
|
||||||
|
case 'libraryMissing':
|
||||||
|
error = info.errorLibrary.replace('%lib', error.library);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'scriptMissing':
|
||||||
|
error = info.errorScript.replace('%lib', error.library);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'errorTooHighVersion':
|
||||||
|
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorTooHighVersion.replace('%used', error.used).replace('%supported', error.supported);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'errorNotSupported':
|
||||||
|
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorNotSupported.replace('%used', error.used);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setStatus('<p>' + info.error + '<br/>' + error + '</p>');
|
$('<li>' + info.error + '<br/>' + error + '</li>').appendTo($log);
|
||||||
};
|
};
|
||||||
|
|
||||||
})(H5P.jQuery, H5P.Version);
|
})(H5P.jQuery, H5P.Version);
|
||||||
|
|
|
@ -7,11 +7,24 @@ H5P.Version = (function () {
|
||||||
* @param {String} version
|
* @param {String} version
|
||||||
*/
|
*/
|
||||||
function Version(version) {
|
function Version(version) {
|
||||||
var versionSplit = version.split('.', 3);
|
|
||||||
|
|
||||||
// Public
|
if (typeof version === 'string') {
|
||||||
this.major =+ versionSplit[0];
|
// Name version string (used by content upgrade)
|
||||||
this.minor =+ versionSplit[1];
|
var versionSplit = version.split('.', 3);
|
||||||
|
this.major =+ versionSplit[0];
|
||||||
|
this.minor =+ versionSplit[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Library objects (used by editor)
|
||||||
|
if (version.localMajorVersion !== undefined) {
|
||||||
|
this.major =+ version.localMajorVersion;
|
||||||
|
this.minor =+ version.localMinorVersion;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.major =+ version.majorVersion;
|
||||||
|
this.minor =+ version.minorVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public. Custom string for this object.
|
* Public. Custom string for this object.
|
||||||
|
|
Loading…
Reference in New Issue