diff --git a/mod/folder/backup/moodle1/lib.php b/mod/folder/backup/moodle1/lib.php new file mode 100644 index 00000000000..ac36e25b8d3 --- /dev/null +++ b/mod/folder/backup/moodle1/lib.php @@ -0,0 +1,91 @@ +. + +/** + * Provides support for the conversion of moodle1 backup to the moodle2 format + * + * @package mod + * @subpackage folder + * @copyright 2011 Andrew Davis + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Folder conversion handler. This resource handler is called by moodle1_mod_resource_handler + */ +class moodle1_mod_folder_handler extends moodle1_mod_handler { + /** @var array in-memory cache for the course module information */ + protected $currentcminfo = null; + /** @var moodle1_file_manager instance */ + protected $fileman = null; + + /** + * Declare the paths in moodle.xml we are able to convert + * + * @return array of {@link convert_path} instances + */ + public function get_paths() { + return array(); + } + + /** + * Converts /MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE data + * Called by moodle1_mod_resource_handler::process_resource() + */ + public function process_resource($data) { + // get the course module id and context id + $instanceid = $data['id']; + $this->currentcminfo = $this->get_cminfo($instanceid); + $moduleid = $this->currentcminfo['id']; + $contextid = $this->converter->get_contextid(CONTEXT_MODULE, $moduleid); + + // we now have all information needed to start writing into the file + $this->open_xml_writer("activities/folder_{$moduleid}/folder.xml"); + $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $moduleid, + 'modulename' => 'folder', 'contextid' => $contextid)); + $this->xmlwriter->begin_tag('folder', array('id' => $instanceid)); + + unset($data['id']); // we already write it as attribute, do not repeat it as child element + foreach ($data as $field => $value) { + $this->xmlwriter->full_tag($field, $value); + } + + // prepare file manager for migrating the folder + $this->fileman = $this->converter->get_file_manager($contextid, 'mod_folder', 'content'); + $this->fileman->migrate_directory('course_files/'.$data['reference']); + } + + public function on_resource_end() { + // close folder.xml + $this->xmlwriter->end_tag('folder'); + $this->xmlwriter->end_tag('activity'); + $this->close_xml_writer(); + + // write inforef.xml for migrated folder + $this->open_xml_writer("activities/folder_{$this->currentcminfo['id']}/inforef.xml"); + $this->xmlwriter->begin_tag('inforef'); + $this->xmlwriter->begin_tag('fileref'); + foreach ($this->fileman->get_fileids() as $fileid) { + $this->write_xml('file', array('id' => $fileid)); + } + $this->xmlwriter->end_tag('fileref'); + $this->xmlwriter->end_tag('inforef'); + $this->close_xml_writer(); + } +} \ No newline at end of file diff --git a/mod/imscp/backup/moodle1/lib.php b/mod/imscp/backup/moodle1/lib.php new file mode 100644 index 00000000000..710e82dc6b2 --- /dev/null +++ b/mod/imscp/backup/moodle1/lib.php @@ -0,0 +1,134 @@ +. + +/** + * Provides support for the conversion of moodle1 backup to the moodle2 format + * + * @package mod + * @subpackage imscp + * @copyright 2011 Andrew Davis + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * imscp conversion handler. This resource handler is called by moodle1_mod_resource_handler + */ +class moodle1_mod_imscp_handler extends moodle1_mod_handler { + /** @var array in-memory cache for the course module information for the current imscp */ + protected $currentcminfo = null; + + //there are two file manager instances as we need to put files in two file areas + + /** @var moodle1_file_manager the file manager instance */ + protected $fileman = null; + + /** + * Declare the paths in moodle.xml we are able to convert + * + * @return array of {@link convert_path} instances + */ + public function get_paths() { + return array(); + } + + /** + * Converts /MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE data + * Called by moodle1_mod_resource_handler::process_resource() + */ + public function process_resource($data) { + global $CFG; + + $instanceid = $data['id']; + $this->currentcminfo = $this->get_cminfo($instanceid); + $moduleid = $this->currentcminfo['id']; + $contextid = $this->converter->get_contextid(CONTEXT_MODULE, $moduleid); + + if ($CFG->texteditors !== 'textarea') { + $data['intro'] = text_to_html($data['intro'], false, false, true); + $data['introformat'] = FORMAT_HTML; + } else { + $data['intro'] = $data['intro']; + $data['introformat'] = FORMAT_MOODLE; + } + + $data['revision'] = 1; + $data['keepold'] = 1; + + //Prepare to migrate the deployed (ie extracted) version of the content package + $this->fileman = $this->converter->get_file_manager($contextid, 'mod_imscp', 'content', $data['revision']); + $this->fileman->migrate_directory('moddata/resource/'.$data['id']); + + // parse manifest + $structure = $this->parse_structure($data, $contextid); + $data['structure'] = is_array($structure) ? serialize($structure) : null; + + // we now have all information needed to start writing into the module file + + $this->open_xml_writer("activities/imscp_{$moduleid}/imscp.xml"); + $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $moduleid, + 'modulename' => 'imscp', 'contextid' => $contextid)); + $this->xmlwriter->begin_tag('imscp', array('id' => $instanceid)); + + unset($data['id']); // we already write it as attribute, do not repeat it as child element + foreach ($data as $field => $value) { + $this->xmlwriter->full_tag($field, $value); + } + + /* We currently do not support undeployed IMS packages + * They need to be deployed (unzipped) to the mod data area then have the ims structure figured out + */ + } + + public function on_resource_end() { + //close imscp.xml + $this->xmlwriter->end_tag('imscp'); + $this->xmlwriter->end_tag('activity'); + $this->close_xml_writer(); + + // write inforef.xml for migrated imscp files + $this->open_xml_writer("activities/imscp_{$this->currentcminfo['id']}/inforef.xml"); + $this->xmlwriter->begin_tag('inforef'); + $this->xmlwriter->begin_tag('fileref'); + foreach ($this->fileman->get_fileids() as $fileid) { + $this->write_xml('file', array('id' => $fileid)); + } + $this->xmlwriter->end_tag('fileref'); + $this->xmlwriter->end_tag('inforef'); + $this->close_xml_writer(); + } + + /// internal implementation details follow ///////////////////////////////// + + /** + * Parse the IMS package structure for the $imscp->structure field + * @param array $data the array of ims package data + */ + protected function parse_structure($data, $contextid) { + global $CFG; + + $temppath = $this->converter->get_tempdir_path(); + $manifestfilecontents = file_get_contents($temppath.'/moddata/resource/'.$data['id'].'/imsmanifest.xml'); + if (empty($manifestfilecontents)) { + return null; + } + + require_once($CFG->dirroot.'/mod/imscp/locallib.php'); + return imscp_parse_manifestfile($manifestfilecontents); + } +} \ No newline at end of file diff --git a/mod/imscp/locallib.php b/mod/imscp/locallib.php index 522cc545bb1..aa39ad8afe8 100644 --- a/mod/imscp/locallib.php +++ b/mod/imscp/locallib.php @@ -78,6 +78,12 @@ function imscp_htmllize_item($item, $imscp, $cm) { return $result; } +/** + * Parse an IMS content package's manifest file to determine its structure + * @param object $imscp + * @param object $context + * @return array + */ function imscp_parse_structure($imscp, $context) { $fs = get_file_storage(); @@ -85,9 +91,17 @@ function imscp_parse_structure($imscp, $context) { return null; } + imscp_parse_manifestfile($manifestfile->get_content()); +} +/** + * Parse the contents of a IMS package's manifest file + * @param string $manifestfilecontents the contents of the manifest file + * @return array + */ +function imscp_parse_manifestfile($manifestfilecontents) { $doc = new DOMDocument(); - if (!$doc->loadXML($manifestfile->get_content(), LIBXML_NONET)) { + if (!$doc->loadXML($manifestfilecontents, LIBXML_NONET)) { return null; } diff --git a/mod/page/backup/moodle1/lib.php b/mod/page/backup/moodle1/lib.php new file mode 100644 index 00000000000..697d34618d4 --- /dev/null +++ b/mod/page/backup/moodle1/lib.php @@ -0,0 +1,131 @@ +. + +/** + * Provides support for the conversion of moodle1 backup to the moodle2 format + * + * @package mod + * @subpackage page + * @copyright 2011 Andrew Davis + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Page conversion handler. This resource handler is called by moodle1_mod_resource_handler + */ +class moodle1_mod_page_handler extends moodle1_mod_handler { + /** @var array in-memory cache for the course module information */ + protected $currentcminfo = null; + /** @var moodle1_file_manager instance */ + protected $fileman = null; + + /** + * Declare the paths in moodle.xml we are able to convert + * + * @return array of {@link convert_path} instances + */ + public function get_paths() { + return array(); + } + + /** + * Converts /MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE data + * Called by moodle1_mod_resource_handler::process_resource() + */ + public function process_resource($data) { + global $CFG; + + // get the course module id and context id + $instanceid = $data['id']; + $cminfo = $this->get_cminfo($instanceid, 'resource'); + $moduleid = $cminfo['id']; + $contextid = $this->converter->get_contextid(CONTEXT_MODULE, $moduleid); + + //we now only support html intros + if ($data['type'] == 'text') { + $data['intro'] = text_to_html($data['intro'], false, false, true); + $data['introformat'] = FORMAT_HTML; + } + + $data['contentformat'] = (int)$data['reference']; + if ($data['contentformat'] < 0 || $data['contentformat'] > 4) { + $data['contentformat'] = FORMAT_MOODLE; + } + + $data['content'] = $data['alltext']; + $data['revision'] = 1; + $data['timemodified'] = time(); + + // convert links to old course files + $originalcourseinfo = $this->converter->get_stash('original_course_info'); + if (!empty($originalcourseinfo) && array_key_exists('original_course_id', $originalcourseinfo)) { + $courseid = $originalcourseinfo['original_course_id']; + + $usedfiles = array("$CFG->wwwroot/file.php/$courseid/", "$CFG->wwwroot/file.php?file=/$courseid/"); + $data['content'] = str_ireplace($usedfiles, '@@PLUGINFILE@@/', $data['content']); + if (strpos($data['content'], '@@PLUGINFILE@@/') === false) { + $data['legacyfiles'] = RESOURCELIB_LEGACYFILES_NO; + } else { + $data['legacyfiles'] = RESOURCELIB_LEGACYFILES_ACTIVE; + } + } else { + $data['legacyfiles'] = RESOURCELIB_LEGACYFILES_NO; + } + + $options = array('printheading'=>0, 'printintro'=>0); + if ($data['popup']) { + $data['display'] = RESOURCELIB_DISPLAY_POPUP; + if ($data['popup']) { + $rawoptions = explode(',', $data['popup']); + foreach ($rawoptions as $rawoption) { + list($name, $value) = explode('=', trim($rawoption), 2); + if ($value > 0 and ($name == 'width' or $name == 'height')) { + $options['popup'.$name] = $value; + continue; + } + } + } + } else { + $data['display'] = RESOURCELIB_DISPLAY_OPEN; + } + $data['displayoptions'] = serialize($options); + + // prepare file manager for migrating the folder + $this->fileman = $this->converter->get_file_manager($contextid, 'mod_page', 'content', 0); + $this->fileman->migrate_directory('moddata/page/'.$data['id']); + + // we now have all information needed to start writing into the file + $this->open_xml_writer("activities/page_{$moduleid}/page.xml"); + $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $moduleid, + 'modulename' => 'page', 'contextid' => $contextid)); + $this->xmlwriter->begin_tag('page', array('id' => $instanceid)); + + unset($data['id']); // we already write it as attribute, do not repeat it as child element + foreach ($data as $field => $value) { + $this->xmlwriter->full_tag($field, $value); + } + } + + public function on_resource_end($data) { + // close page.xml + $this->xmlwriter->end_tag('page'); + $this->xmlwriter->end_tag('activity'); + $this->close_xml_writer(); + } +} \ No newline at end of file diff --git a/mod/resource/backup/moodle1/lib.php b/mod/resource/backup/moodle1/lib.php new file mode 100644 index 00000000000..8cacdd66d8f --- /dev/null +++ b/mod/resource/backup/moodle1/lib.php @@ -0,0 +1,267 @@ +. + +/** + * Provides support for the conversion of moodle1 backup to the moodle2 format + * + * @package mod + * @subpackage forum + * @copyright 2011 Mark Nielsen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Forum conversion handler + */ +class moodle1_mod_resource_handler extends moodle1_mod_handler { + /** @var array in-memory cache for the course module information */ + protected $currentcminfo = null; + /** @var moodle1_file_manager instance */ + protected $fileman = null; + + /** + * Declare the paths in moodle.xml we are able to convert + * + * The method returns list of {@link convert_path} instances. + * For each path returned, the corresponding conversion method must be + * defined. + * + * Note that the paths /MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE do not + * actually exist in the file. The last element with the module name was + * appended by the moodle1_converter class. + * + * @return array of {@link convert_path} instances + */ + public function get_paths() { + return array( + new convert_path( + 'resource', '/MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE', + array( + 'renamefields' => array( + 'summary' => 'intro', + ), + 'newfields' => array( + 'introformat' => 0, + ), + 'dropfields' => array( + 'modtype', + ), + ) + ) + ); + } + + /** + * Converts /MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE data + */ + public function process_resource(array $data, array $raw) { + global $CFG; + require_once("$CFG->libdir/resourcelib.php"); + + //if this is a file or URL resource we need to deal with the options + //before possibly branching out to the URL successor + if ($data['type'] == 'file') { + $options = array('printheading'=>0, 'printintro'=>1); + if ($data['options'] == 'frame') { + $data['display'] = RESOURCELIB_DISPLAY_FRAME; + + } else if ($data['options'] == 'objectframe') { + $data['display'] = RESOURCELIB_DISPLAY_EMBED; + + } else if ($data['options'] == 'forcedownload') { + $data['display'] = RESOURCELIB_DISPLAY_DOWNLOAD; + + } else if ($data['popup']) { + $data['display'] = RESOURCELIB_DISPLAY_POPUP; + if ($data['popup']) { + $rawoptions = explode(',', $data['popup']); + foreach ($rawoptions as $rawoption) { + list($name, $value) = explode('=', trim($rawoption), 2); + if ($value > 0 and ($name == 'width' or $name == 'height')) { + $options['popup'.$name] = $value; + continue; + } + } + } + + } else { + $data['display'] = RESOURCELIB_DISPLAY_AUTO; + } + $data['displayoptions'] = serialize($options); + unset($data['popup']); + } + + // fix invalid NULL popup and options data in old mysql databases + if (!array_key_exists ('popup', $data) || $data['popup'] === null) { + $data['popup'] = ''; + } + if (!array_key_exists ('options', $data) || $data['options'] === null) { + $data['options'] = ''; + } + + if ($successor = $this->get_successor($data['type'], $data['reference'])) { + // the instance id will be kept + $instanceid = $data['id']; + + // move the instance from the resource's modinfo stash to the successor's + // modinfo stash + $resourcemodinfo = $this->converter->get_stash('modinfo_resource'); + $successormodinfo = $this->converter->get_stash('modinfo_'.$successor->get_modname()); + $successormodinfo['instances'][$instanceid] = $resourcemodinfo['instances'][$instanceid]; + unset($resourcemodinfo['instances'][$instanceid]); + $this->converter->set_stash('modinfo_resource', $resourcemodinfo); + $this->converter->set_stash('modinfo_'.$successor->get_modname(), $successormodinfo); + + // get the course module information for the legacy resource module + $cminfo = $this->get_cminfo($instanceid); + + // use the version of the successor instead of the current mod/resource + // beware - the version.php declares info via $module object, do not use + // a variable of such name here + include $CFG->dirroot.'/mod/'.$successor->get_modname().'/version.php'; + $cminfo['version'] = $module->version; + + // stash the new course module information for this successor + $cminfo['modulename'] = $successor->get_modname(); + $this->converter->set_stash('cminfo_'.$cminfo['modulename'], $cminfo, $instanceid); + + // delegate the processing to the successor handler + return $successor->process_resource($data, $raw); + } + + //only $data['type'] == "file" should get to here + + // get the course module id and context id + $instanceid = $data['id']; + $this->currentcminfo = $this->get_cminfo($instanceid); + $moduleid = $this->currentcminfo['id']; + $contextid = $this->converter->get_contextid(CONTEXT_MODULE, $moduleid); + + unset($data['type']); + unset($data['alltext']); + unset($data['popup']); + unset($data['options']); + + $data['tobemigrated'] = 0; + $data['mainfile'] = null; + $data['legacyfiles'] = 0; + $data['legacyfileslast'] = null; + $data['display'] = 0; + $data['displayoptions'] = null; + $data['filterfiles'] = 0; + $data['revision'] = 0; + unset($data['mainfile']); + + // we now have all information needed to start writing into the file + $this->open_xml_writer("activities/resource_{$moduleid}/resource.xml"); + $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $moduleid, + 'modulename' => 'resource', 'contextid' => $contextid)); + $this->xmlwriter->begin_tag('resource', array('id' => $instanceid)); + + unset($data['id']); // we already write it as attribute, do not repeat it as child element + foreach ($data as $field => $value) { + $this->xmlwriter->full_tag($field, $value); + } + + // prepare file manager for migrating the resource file + $this->fileman = $this->converter->get_file_manager($contextid, 'mod_resource', 'content'); + $this->fileman->migrate_file('course_files/'.$data['reference']); + } + + public function on_resource_end(array $data) { + if ($successor = $this->get_successor($data['type'], $data['reference'])) { + $successor->on_resource_end($data); + } else { + $this->xmlwriter->end_tag('resource'); + $this->xmlwriter->end_tag('activity'); + $this->close_xml_writer(); + + // write inforef.xml for migrated resource file. + $this->open_xml_writer("activities/resource_{$this->currentcminfo['id']}/inforef.xml"); + $this->xmlwriter->begin_tag('inforef'); + $this->xmlwriter->begin_tag('fileref'); + foreach ($this->fileman->get_fileids() as $fileid) { + $this->write_xml('file', array('id' => $fileid)); + } + $this->xmlwriter->end_tag('fileref'); + $this->xmlwriter->end_tag('inforef'); + $this->close_xml_writer(); + } + } + + /// internal implementation details follow ///////////////////////////////// + + /** + * Returns the handler of the new 2.0 mod type according the given type of the legacy 1.9 resource + * + * @param string $type the value of the 'type' field in 1.9 resource + * @param string $reference a file path. Necessary to differentiate files from web URLs + * @throws moodle1_convert_exception for the unknown types + * @return null|moodle1_mod_handler the instance of the handler, or null if the type does not have a successor + */ + protected function get_successor($type, $reference) { + static $successors = array(); + + switch ($type) { + case 'text': + case 'html': + $name = 'page'; + break; + case 'directory': + $name = 'folder'; + break; + case 'ims': + $name = 'imscp'; + break; + case 'file': + // if http:// https:// ftp:// OR starts with slash need to be converted to URL + if (strpos($reference, '://') or strpos($reference, '/') === 0) { + $name = 'url'; + } else { + $name = null; + } + break; + default: + throw new moodle1_convert_exception('unknown_resource_successor', $type); + } + + if (is_null($name)) { + return null; + } + + if (!isset($successors[$name])) { + $class = 'moodle1_mod_'.$name.'_handler'; + $successors[$name] = new $class($this->converter, 'mod', $name); + + // add the successor into the modlist stash + $modnames = $this->converter->get_stash('modnameslist'); + $modnames[] = $name; + $modnames = array_unique($modnames); // should not be needed but just in case + $this->converter->set_stash('modnameslist', $modnames); + + // add the successor's modinfo stash + $modinfo = $this->converter->get_stash('modinfo_resource'); + $modinfo['name'] = $name; + $modinfo['instances'] = array(); + $this->converter->set_stash('modinfo_'.$name, $modinfo); + } + + return $successors[$name]; + } +} \ No newline at end of file diff --git a/mod/url/backup/moodle1/lib.php b/mod/url/backup/moodle1/lib.php new file mode 100644 index 00000000000..2d003b2b7be --- /dev/null +++ b/mod/url/backup/moodle1/lib.php @@ -0,0 +1,74 @@ +. + +/** + * Provides support for the conversion of moodle1 backup to the moodle2 format + * + * @package mod + * @subpackage url + * @copyright 2011 Andrew Davis + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * URL conversion handler. This resource handler is called by moodle1_mod_resource_handler + */ +class moodle1_mod_url_handler extends moodle1_mod_handler { + + /** + * Declare the paths in moodle.xml we are able to convert + * + * @return array of {@link convert_path} instances + */ + public function get_paths() { + return array(); + } + + /** + * Converts /MOODLE_BACKUP/COURSE/MODULES/MOD/RESOURCE data + * Called by moodle1_mod_resource_handler::process_resource() + */ + public function process_resource($data) { + $data['externalurl'] = $data['reference']; + unset($data['reference']); + + // get the course module id and context id + $instanceid = $data['id']; + $cminfo = $this->get_cminfo($instanceid, 'resource'); + $moduleid = $cminfo['id']; + $contextid = $this->converter->get_contextid(CONTEXT_MODULE, $moduleid); + + // we now have all information needed to start writing into the file + $this->open_xml_writer("activities/url_{$moduleid}/url.xml"); + $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $moduleid, + 'modulename' => 'url', 'contextid' => $contextid)); + $this->xmlwriter->begin_tag('url', array('id' => $instanceid)); + + unset($data['id']); // we already write it as attribute, do not repeat it as child element + foreach ($data as $field => $value) { + $this->xmlwriter->full_tag($field, $value); + } + } + + public function on_resource_end() { + $this->xmlwriter->end_tag('url'); + $this->xmlwriter->end_tag('activity'); + $this->close_xml_writer(); + } +} \ No newline at end of file