Commit d1173a45 authored by Svein-Tore Griff With's avatar Svein-Tore Griff With

Issue #2120227 by gafolini, Ellinokon and falcon: Add export feature to H5P

parent 5f18896d
......@@ -77,7 +77,7 @@ class H5PDrupal implements H5PFrameworkInterface {
$library['machineName'], $library['majorVersion'], $library['minorVersion'], $library['patchVersion']));
return $result === '1';
}
/**
* Implements isInDevMode
*/
......@@ -212,7 +212,7 @@ class H5PDrupal implements H5PFrameworkInterface {
);
// @todo: Add support for allowing the user to select embed type
}
/**
* Implement getWhitelist
*/
......@@ -332,7 +332,7 @@ class H5PDrupal implements H5PFrameworkInterface {
return $semantics;
}
private function getSemanticsFromFile($machineName, $majorVersion, $minorVersion) {
$semanticsPath = file_create_path(file_directory_path() . '/' . variable_get('h5p_default_path', 'h5p') . '/libraries/' . $machineName . '-' . $majorVersion . '.' . $minorVersion . '/semantics.json');
if (file_exists($semanticsPath)) {
......@@ -344,6 +344,66 @@ class H5PDrupal implements H5PFrameworkInterface {
}
return FALSE;
}
/**
* @param int $contentId
* ContentID of the node we are going to export
* @param string $title
* Title of the node to export
* @param string $language
* Language of the node to export
* @return array
* An array with all the data needed to export the h5p.
**/
public function getExportData($contentId, $title, $language) {
$content = db_fetch_array(db_query(
"SELECT main_library_id, embed_type
FROM h5p_nodes
WHERE content_id = %d",
$contentId));
$mainLibraryId = $content['main_library_id'];
// Use library ids to get library info.
$machineNameQuery = db_query(
"SELECT hl.machine_name as machine_name, hl.major_version as major_version, hl.minor_version as minor_version, hnl.preloaded as preloaded, hl.library_id as library_id
FROM {h5p_libraries} hl
JOIN {h5p_nodes_libraries} hnl ON hl.library_id = hnl.library_id
WHERE hnl.content_id = %d", $contentId);
while($libs = db_fetch_array($machineNameQuery)) {
$librariesInfo[] = array(
'machine_name' => $libs['machine_name'],
'major_version' => $libs['major_version'],
'minor_version' => $libs['minor_version'],
'preloaded' => $libs['preloaded'],
);
// Save the main libary machine name.
if ($libs['library_id'] == $mainLibraryId) {
$mainLibrary = $libs['machine_name'];
}
}
// Set language to drupals node language, or 'und' if not set.
$exportLanguage = $language === TRUE ? $language : 'und';
$export = array(
'title' => $title,
'contentId' => $contentId,
'mainLibrary' => $mainLibrary,
'embed_type' => $content['embed_type'],
'libraries' => $librariesInfo,
'language' => $exportLanguage,
);
return $export;
}
/**
* Check if h5p export is enabled.
*
* @return bool
*/
public function exportEnabled() {
return (bool) variable_get('h5p_export', 1);
}
}
?>
......@@ -269,6 +269,7 @@ function h5p_requirements($phase) {
// File paths
$h5p_path = file_create_path(file_directory_path() . '/' . variable_get('h5p_default_path', 'h5p'));
$temp_path = $h5p_path . '/temp';
$export_path = $h5p_path . '/exports';
if (!file_check_directory($h5p_path, FILE_CREATE_DIRECTORY)) {
$requirements['h5p_dirs'] = array(
'value' => t('Missing directory.'),
......@@ -283,6 +284,13 @@ function h5p_requirements($phase) {
'description' => t("The h5p module's temp directory %temp_path is missing.", array('%temp_path' => $temp_path)),
);
}
else if (!file_check_directory($export_path, FILE_CREATE_DIRECTORY)) {
$requirements['h5p_dirs'] = array(
'value' => t('Missing export directory.'),
'severity' => REQUIREMENT_ERROR,
'description' => t("The h5p module's export directory %export_path is missing.", array('%export_path' => $export_path)),
);
}
else {
$requirements['h5p_dirs'] = array(
'value' => t('Exists (%path).', array('%path' => $h5p_path)),
......
......@@ -40,6 +40,17 @@ function h5p_menu() {
'type' => MENU_NORMAL_ITEM,
'file' => 'h5p.admin.inc',
);
//Check if export is enabled and toggle menu callback.
if(_h5p_get_instance('interface')->exportEnabled()) {
$items['node/%node/h5p-export'] = array(
'title' => 'h5p-export',
'page callback' => 'h5p_export_callback',
'access callback' => 'variable_get',
'access arguments' => array('h5p_export',1),
'page arguments' => array(1),
'type' => MENU_CALLBACK,
);
}
return $items;
}
......@@ -224,6 +235,11 @@ function h5p_update($node) {
WHERE content_id = %d", $node->json_content, $node->embed_type, $node->main_library_id, h5p_get_content_id($node)
);
}
$export_path = _h5p_get_h5p_path() . '/exports/' . $node->nid . '.h5p';
if (file_exists($export_path)) {
file_delete($export_path);
}
cache_clear_all('validated_json_'.$node->vid, 'cache');
}
......@@ -370,6 +386,7 @@ function h5p_add_files_and_settings($node, $mode) {
),
),
'jsonContentPath' => base_path() . _h5p_get_h5p_path() . '/content/',
'export' => _h5p_get_instance('interface')->exportEnabled(),
)
);
......@@ -458,6 +475,7 @@ function _h5p_check_settings() {
$temp_path = $path . '/temp';
$libraries_path = $path . '/libraries';
$content_path = $path . '/content';
$export_path = $path . '/exports';
if (!file_check_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
return FALSE;
......@@ -471,6 +489,9 @@ function _h5p_check_settings() {
if (!file_check_directory($content_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
return FALSE;
}
if (!file_check_directory($export_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
return FALSE;
}
return TRUE;
}
......@@ -519,6 +540,8 @@ function _h5p_get_instance($type) {
return new H5PStorage($interface, $core);
case 'contentvalidator':
return new H5PContentValidator($interface, $core);
case 'export':
return new H5PExport($interface, $core);
case 'interface':
return $interface;
case 'core':
......@@ -568,4 +591,17 @@ function _h5p_clear_js_and_css_cache() {
*/
function h5p_get_content_id($node) {
return variable_get('h5p_revisioning', 1) ? $node->vid : $node->nid;
}
\ No newline at end of file
}
/**
* Callback requesting h5p package.
*
* @param object $node
* The node we will extract the contet id from
* @return h5p-package
* The h5p package.
**/
function h5p_export_callback($node) {
$content_id = h5p_get_content_id($node);
return _h5p_get_instance('export')->exportToZip(_h5p_get_instance('interface')->getExportData($content_id, $node->title, $node->language));
}
......@@ -28,6 +28,10 @@ H5PIntegration.getContentPath = function (contentId) {
}
};
H5PIntegration.getExport = function() {
return Drupal.settings.h5p.export;
}
/**
* Get the path to the library
*
......
......@@ -219,6 +219,122 @@ interface H5PFrameworkInterface {
* Library Id
*/
public function deleteLibraryDependencies($libraryId);
/**
* Get the paths we need to export
*
* @param int $contentId
* @param string $title
* @param string $language
* @return export object
*/
public function getExportData($contentId, $title, $language);
/**
* Check if export is enabled.
*/
public function exportEnabled();
}
/**
* This class is used for exporting zips
*/
Class H5PExport {
public $h5pF;
public $h5pC;
/**
* Constructor for the H5PStorage
*
* @param object $H5PFramework
* The frameworks implementation of the H5PFrameworkInterface
*/
public function __construct($H5PFramework, $H5PCore) {
$this->h5pF = $H5PFramework;
$this->h5pC = $H5PCore;
}
/**
* Create the h5p package
*
* @param object $exports
* The data to be exported.
* @return h5p package.
*/
public function exportToZip($exports) {
$h5pDir = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR;
$tempPath = $h5pDir . 'temp' . DIRECTORY_SEPARATOR . $exports['contentId'];
$zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $exports['contentId'] . '.h5p';
// Check if h5p-package already exists.
if (!file_exists($zipPath) == true) {
// Temp dir to put the h5p files in
@mkdir($tempPath);
$this->h5pC->copyTree($h5pDir . 'content' . DIRECTORY_SEPARATOR . $exports['contentId'], $tempPath . DIRECTORY_SEPARATOR . 'content');
// Copies libraries to temp dir and create mention in h5p.json
foreach($exports['libraries'] as $library) {
$source = $h5pDir . 'libraries' . DIRECTORY_SEPARATOR . $library['machine_name'] . '-' . $library['major_version'] . '.' . $library['minor_version'];
$destination = $tempPath . DIRECTORY_SEPARATOR . $library['machine_name'];
$this->h5pC->copyTree($source, $destination);
// Set preloaded and dynamic dependencies
if ($library['preloaded']) {
$preloadedDependencies[] = array(
'machineName' => $library['machine_name'],
'majorVersion' => $library['major_version'],
'minorVersion' => $library['minor_version'],
);
} else {
$dynamicDependencies[] = array(
'machineName' => $library['machine_name'],
'majorVersion' => $library['major_version'],
'minorVersion' => $library['minor_version'],
);
}
}
// Make embedTypes into an array
$embedTypes = explode(', ', $exports['embed_type']);
// Build h5p.json
$h5pJson = array (
'title' => $exports['title'],
'language' => $exports['language'],
'mainLibrary' => $exports['mainLibrary'],
'embedTypes' => $embedTypes,
);
// Add preloaded and dynamic dependencies if they exist
if ($preloadedDependencies) { $h5pJson['preloadedDependencies'] = $preloadedDependencies; }
if ($dynamicDependencies) { $h5pJson['dynamicDependencies'] = $dynamicDependencies; }
// Save h5p.json
$results = print_r(json_encode($h5pJson), true);
file_put_contents($tempPath . DIRECTORY_SEPARATOR . 'h5p.json', $results);
// Create new zip instance.
$zip = new ZipArchive();
$zip->open($zipPath, ZIPARCHIVE::CREATE);
// Get all files and folders in $tempPath
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tempPath . DIRECTORY_SEPARATOR));
// Add files to zip
foreach ($iterator as $key=>$value) {
$test = '.';
// Do not add the folders '.' and '..' to the zip. This will make zip invalid.
if (substr_compare($key, $test, -strlen($test), strlen($test)) !== 0) {
// Get files path in $tempPath
$filePath = explode($tempPath . DIRECTORY_SEPARATOR, $key);
// Add files to the zip with the intended file-structure
$zip->addFile($key, $filePath[1]);
}
}
// Close zip and remove temp dir
$zip->close();
@rmdir($tempPath);
}
// Set headers for automagic download!!
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . $exports['title'] . '.h5p');
readfile ($zipPath);
}
}
/**
......
......@@ -62,6 +62,10 @@ H5P.init = function () {
H5P.fullScreen($el, obj);
return false;
});
};
if (H5PIntegration.getExport()) {
H5P.jQuery('<div class="h5p-export"><a href="' + window.location + '/h5p-export">Last ned H5P</a></div>').insertAfter($el).children();
}
});
......@@ -435,4 +439,4 @@ if (H5P.jQuery) {
H5P.init();
}
});
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment