From: skodak Date: Thu, 13 Aug 2009 20:48:32 +0000 (+0000) Subject: MDL-20067 new IMS Content package module, includes migrate from old mod/resource... X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=2ff648fb972b5116a66e2167778b01a776e76ab7;p=moodle.git MDL-20067 new IMS Content package module, includes migrate from old mod/resource; remaining issues to be listed in tracker as sub-tasks --- diff --git a/lang/en_utf8/imscp.php b/lang/en_utf8/imscp.php new file mode 100644 index 0000000000..5d71ccbdd4 --- /dev/null +++ b/lang/en_utf8/imscp.php @@ -0,0 +1,13 @@ +. + +/** + * Capability definitions for the imscp module. + * + * @package mod-imscp + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$mod_imscp_capabilities = array( + +/* TODO: review public portfolio API first! + 'mod/imscp:portfolioexport' => array( + + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + ) + ),*/ + +); + diff --git a/mod/imscp/db/install.php b/mod/imscp/db/install.php new file mode 100644 index 0000000000..90f1e81a2b --- /dev/null +++ b/mod/imscp/db/install.php @@ -0,0 +1,51 @@ +. + +/** + * Post installation and migration code. + * + * This file replaces: + * - STATEMENTS section in db/install.xml + * - lib.php/modulename_install() post installation hook + * - partially defaults.php + * + * @package mod-imscp + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function xmldb_imscp_install() { + global $CFG; + + // Install logging support + update_log_display_entry('imscp', 'view', 'imscp', 'name'); + update_log_display_entry('imscp', 'view all', 'imscp', 'name'); + update_log_display_entry('imscp', 'update', 'imscp', 'name'); + update_log_display_entry('imscp', 'add', 'imscp', 'name'); + + // Upgrade from old resource module type if needed + require_once("$CFG->dirroot/mod/imscp/db/upgradelib.php"); + imscp_20_migrate(); +} + +function xmldb_imscp_install_recovery() { + global $CFG; + + // Upgrade from old resource module type if needed + require_once("$CFG->dirroot/mod/imscp/db/upgradelib.php"); + imscp_20_migrate(); +} diff --git a/mod/imscp/db/install.xml b/mod/imscp/db/install.xml new file mode 100644 index 0000000000..0ca98320a8 --- /dev/null +++ b/mod/imscp/db/install.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/mod/imscp/db/upgrade.php b/mod/imscp/db/upgrade.php new file mode 100644 index 0000000000..e542ca4607 --- /dev/null +++ b/mod/imscp/db/upgrade.php @@ -0,0 +1,34 @@ +. + +/** + * IMS CP module upgrade code + * + * @package mod-imscp + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +function xmldb_imscp_upgrade($oldversion) { + global $CFG, $DB; + + $dbman = $DB->get_manager(); + $result = true; + + + return $result; +} diff --git a/mod/imscp/db/upgradelib.php b/mod/imscp/db/upgradelib.php new file mode 100644 index 0000000000..1319c41d36 --- /dev/null +++ b/mod/imscp/db/upgradelib.php @@ -0,0 +1,147 @@ +. + +/** + * IMS CP module upgrade related helper functions + * + * @package mod-imscp + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Migrate imscp module data from 1.9 resource_old table to new imscp table + * @return void + */ +function imscp_20_migrate() { + global $CFG, $DB; + require_once("$CFG->libdir/filelib.php"); + require_once("$CFG->dirroot/course/lib.php"); + require_once("$CFG->dirroot/mod/imscp/locallib.php"); + + if (!file_exists("$CFG->dirroot/mod/resource/db/upgradelib.php")) { + // bad luck, somebody deleted resource module + return; + } + + require_once("$CFG->dirroot/mod/resource/db/upgradelib.php"); + + // create resource_old table and copy resource table there if needed + if (!resource_20_prepare_migration()) { + // no modules or fresh install + return; + } + + if (!$candidates = $DB->get_recordset('resource_old', array('type'=>'ims', 'migrated'=>0))) { + return; + } + + $fs = get_file_storage(); + + foreach ($candidates as $candidate) { + upgrade_set_timeout(60); + + $imscp = new object(); + $imscp->course = $candidate->course; + $imscp->name = $candidate->name; + $imscp->intro = $candidate->intro; + $imscp->introformat = $candidate->introformat; + $imscp->revision = 1; + $imscp->keepold = 1; + $imscp->timemodified = time(); + + if (!$imscp = resource_migrate_to_module('imscp', $candidate, $imscp)) { + continue; + } + + $context = get_context_instance(CONTEXT_MODULE, $candidate->cmid); + $root = "$CFG->dataroot/$candidate->course/$CFG->moddata/resource/$candidate->oldid"; + + // migrate package backup file + if ($candidate->reference) { + $package = basename($candidate->reference); + $fullpath = $root.'/'.$package; + if (file_exists($fullpath)) { + $file_record = array('contextid' => $context->id, + 'filearea' => 'imscp_backup', + 'itemid' => 1, + 'filepath' => '/', + 'filename' => $package); + $fs->create_file_from_pathname($file_record, $fullpath); + } + } + + // migrate extracted package data + $files = imsc_migrate_get_old_files($root, ''); + $file_record = array('contextid'=>$context->id, 'filearea'=>'imscp_content', 'itemid'=>1); + $error = false; + foreach ($files as $relname=>$fullpath) { + $parts = explode('/', $relname); + $file_record['filename'] = array_pop($parts); + $parts[] = ''; // keep trailing slash + $file_record['filepath'] = implode('/', $parts); + + try { + $fs->create_file_from_pathname($file_record, $fullpath); + } catch (Exception $e) { + //continue on error, we can not recover anyway + $error = true; + notify("IMSCP: failed migrating file: $relname"); + } + } + unset($files); + + // parse manifest + $structure = imscp_parse_structure($imscp, $context); + $imscp->structure = is_array($structure) ? serialize($structure) : null; + $DB->update_record('imscp', $imscp); + + // remove old moddata dir only if no error and manifest ok + if (!$error and is_array($structure)) { + fulldelete($root); + } + } + + $candidates->close(); + + // clear all course modinfo caches + rebuild_course_cache(0, true); +} + +/** + * Private function returning all extracted IMS content package file + */ +function imsc_migrate_get_old_files($path, $relative) { + $result = array(); + $items = new DirectoryIterator($path); + foreach ($items as $item) { + if ($item->isDot() or $item->isLink()) { + // symbolik links could create infinite loops or cause unintended file migration, sorry + continue; + } + $pathname = $item->getPathname(); + $relname = $relative.'/'.$item->getFilename(); + if ($item->isFile()) { + $result[$relname] = $pathname; + } else if ($item->isDir()) { + $result = array_merge($result, imsc_migrate_get_old_files($pathname, $relname)); + } + unset($item); + } + unset($items); + return $result; +} \ No newline at end of file diff --git a/mod/imscp/functions.js b/mod/imscp/functions.js new file mode 100644 index 0000000000..2439a5ec67 --- /dev/null +++ b/mod/imscp/functions.js @@ -0,0 +1,279 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Javascript helper function for IMS Content Package module including + * dummy SCORM API. + * + * @package mod-imscp + * @copyright 2009 Petr Skoda (http://skodak.org) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** Dummy SCORM API adapter */ +var API = new function () { + this.LMSCommit = function (parameter) {return "true";}; + this.LMSFinish = function (parameter) {return "true";}; + this.LMSGetDiagnostic = function (errorCode) {return "n/a";}; + this.LMSGetErrorString = function (errorCode) {return "n/a";}; + this.LMSGetLastError = function () {return "0";}; + this.LMSGetValue = function (element) {return "";}; + this.LMSInitialize = function (parameter) {return "true";}; + this.LMSSetValue = function (element, value) {return "true";}; +}; + +var imscp_layout_widget; +var imscp_current_node; +var imscp_buttons = []; +var imscp_bloody_labelclick = false; +var imscp_panel; + +function imscp_init() { + YAHOO.util.Event.onDOMReady(function () { + imscp_setup(); + }); +} + +function imscp_setup() { + // layout + YAHOO.widget.LayoutUnit.prototype.STR_COLLAPSE = mstr.moodle.hide; + YAHOO.widget.LayoutUnit.prototype.STR_EXPAND = mstr.moodle.show; + + imscp_layout_widget = new YAHOO.widget.Layout('imscp_layout', { + minWidth: 600, + minHeight: 400, + units: [ + { position: 'left', body: 'imscp_toc', header: mstr.imscp.toc, width: 250, resize: true, gutter: '2px 5px 5px 2px', collapse: true, minWidth:150}, + { position: 'center', body: '
', gutter: '2px 5px 5px 2px', scroll: true} + ] + }); + imscp_layout_widget.render(); + var left = imscp_layout_widget.getUnitByPosition('left'); + left.on('collapse', function() { + imscp_resize_frame(); + }); + left.on('expand', function() { + imscp_resize_frame(); + }); + + // ugly resizing hack that works around problems with resizing of iframes and objects + left._resize.on('startResize', function() { + var obj = YAHOO.util.Dom.get('imscp_object'); + obj.style.display = 'none'; + }); + left._resize.on('endResize', function() { + var obj = YAHOO.util.Dom.get('imscp_object'); + obj.style.display = 'block'; + imscp_resize_frame(); + }); + + // TOC tree + var tree = new YAHOO.widget.TreeView('imscp_tree'); + tree.singleNodeHighlight = true; + tree.subscribe('labelClick', function(node) { + imscp_activate_item(node); + if (node.children.length) { + imscp_bloody_labelclick = true; + } + }); + tree.subscribe('collapse', function(node) { + if (imscp_bloody_labelclick) { + imscp_bloody_labelclick = false; + return false; + } + }); + tree.subscribe('expand', function(node) { + if (imscp_bloody_labelclick) { + imscp_bloody_labelclick = false; + return false; + } + }); + tree.expandAll(); + tree.render(); + + // navigation + imscp_panel = new YAHOO.widget.Panel('imscp_navpanel', { visible:true, draggable:true, close:false, + context: ['page', 'bl', 'bl', ["windowScroll", "textResize", "windowResize"]], constraintoviewport:true} ); + imscp_panel.setHeader(mstr.imscp.navigation); + //TODO: make some better&accessible buttons + imscp_panel.setBody(''); + imscp_panel.render(); + imscp_buttons[0] = new YAHOO.widget.Button('nav_skipprev'); + imscp_buttons[1] = new YAHOO.widget.Button('nav_prev'); + imscp_buttons[2] = new YAHOO.widget.Button('nav_up'); + imscp_buttons[3] = new YAHOO.widget.Button('nav_next'); + imscp_buttons[4] = new YAHOO.widget.Button('nav_skipnext'); + imscp_buttons[0].on('click', function(ev) { + imscp_activate_item(imscp_skipprev(imscp_current_node)); + }); + imscp_buttons[1].on('click', function(ev) { + imscp_activate_item(imscp_prev(imscp_current_node)); + }); + imscp_buttons[2].on('click', function(ev) { + imscp_activate_item(imscp_up(imscp_current_node)); + }); + imscp_buttons[3].on('click', function(ev) { + imscp_activate_item(imscp_next(imscp_current_node)); + }); + imscp_buttons[4].on('click', function(ev) { + imscp_activate_item(imscp_skipnext(imscp_current_node)); + }); + imscp_panel.render(); + + // finally activate the first item + imscp_activate_item(tree.getRoot().children[0]); + + // resizing + imscp_resize_layout(false); + + // fix layout if window resized + window.onresize = function() { + imscp_resize_layout(true); + }; +} + + +function imscp_activate_item(node) { + if (!node) { + return; + } + imscp_current_node = node; + imscp_current_node.highlight(); + + var content = new YAHOO.util.Element('imscp_content'); + try { + // first try IE way - it can not set name attribute later + // and also it has some restrictions on DOM access from object tag + var obj = document.createElement('