From 8be3d5ab030ab215333ebba7af07fdf5b0c10d47 Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sun, 21 Oct 2012 15:56:01 +0800 Subject: [PATCH] MDL-35297 book: replay some steps lost when book landed to core This commit replays, conditionally, all the upgrade steps from MOODLE_19_STABLE to MOODLE_23_STABLE in the mod_book activity. That guarentees that any site using the mod_book before landing to core, no matter if it was the latest or an outdated one will upgrade perfectly to the expected current version. As a general rule, everytime one contrib plugin lands to core, its complete upgrade code must be kept, at least until the core version that introduced it, is out completely from the upgrade requirement conditions. In this case, with the missing upgrade code being added to 2.4, it will be safe to delete the upgrade steps once 2.5 (or upwards) become a requirement. Never always. Conflicts: mod/book/version.php --- mod/book/db/upgrade.php | 146 ++++++++++++++++++++++++++++++++ mod/book/db/upgradelib.php | 168 +++++++++++++++++++++++++++++++++++++ mod/book/version.php | 2 +- 3 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 mod/book/db/upgradelib.php diff --git a/mod/book/db/upgrade.php b/mod/book/db/upgrade.php index 3fb10859cf3..c4709f003cd 100644 --- a/mod/book/db/upgrade.php +++ b/mod/book/db/upgrade.php @@ -40,6 +40,152 @@ function xmldb_book_upgrade($oldversion) { // Moodle v2.3.0 release upgrade line // Put any upgrade step following this + // Note: The next steps (up to 2012061710 included, are a "replay" of old upgrade steps, + // because some sites updated to Moodle 2.3 didn't have the latest contrib mod_book + // installed, so some required changes were missing. + // + // All the steps are run conditionally so sites upgraded from latest contrib mod_book or + // new (2.3 and upwards) sites won't get affected. + // + // See MDL-35297 and commit msg for more information. + + if ($oldversion < 2012061703) { + // Rename field summary on table book to intro + $table = new xmldb_table('book'); + $field = new xmldb_field('summary', XMLDB_TYPE_TEXT, null, null, null, null, null, 'name'); + + // Launch rename field summary + if ($dbman->field_exists($table, $field)) { + $dbman->rename_field($table, $field, 'intro'); + } + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061703, 'book'); + } + + if ($oldversion < 2012061704) { + // Define field introformat to be added to book + $table = new xmldb_table('book'); + $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'intro'); + + // Launch add field introformat + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + // Conditionally migrate to html format in intro + // Si está activo el htmleditor!!!!! + if ($CFG->texteditors !== 'textarea') { + $rs = $DB->get_recordset('book', array('introformat'=>FORMAT_MOODLE), '', 'id,intro,introformat'); + foreach ($rs as $b) { + $b->intro = text_to_html($b->intro, false, false, true); + $b->introformat = FORMAT_HTML; + $DB->update_record('book', $b); + upgrade_set_timeout(); + } + unset($b); + $rs->close(); + } + } + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061704, 'book'); + } + + if ($oldversion < 2012061705) { + // Define field introformat to be added to book + $table = new xmldb_table('book_chapters'); + $field = new xmldb_field('contentformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'content'); + + // Launch add field introformat + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + + $DB->set_field('book_chapters', 'contentformat', FORMAT_HTML, array()); + } + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061705, 'book'); + } + + if ($oldversion < 2012061706) { + require_once("$CFG->dirroot/mod/book/db/upgradelib.php"); + + $sqlfrom = "FROM {book} b + JOIN {modules} m ON m.name = 'book' + JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = b.id)"; + + $count = $DB->count_records_sql("SELECT COUNT('x') $sqlfrom"); + + if ($rs = $DB->get_recordset_sql("SELECT b.id, b.course, cm.id AS cmid $sqlfrom ORDER BY b.course, b.id")) { + + $pbar = new progress_bar('migratebookfiles', 500, true); + + $i = 0; + foreach ($rs as $book) { + $i++; + upgrade_set_timeout(360); // set up timeout, may also abort execution + $pbar->update($i, $count, "Migrating book files - $i/$count."); + + $context = context_module::instance($book->cmid); + + mod_book_migrate_moddata_dir_to_legacy($book, $context, '/'); + + // remove dirs if empty + @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id/"); + @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/book/"); + @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/"); + @rmdir("$CFG->dataroot/$book->course/"); + } + $rs->close(); + } + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061706, 'book'); + } + + if ($oldversion < 2012061707) { + // Define field disableprinting to be dropped from book + $table = new xmldb_table('book'); + $field = new xmldb_field('disableprinting'); + + // Conditionally launch drop field disableprinting + if ($dbman->field_exists($table, $field)) { + $dbman->drop_field($table, $field); + } + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061707, 'book'); + } + + if ($oldversion < 2012061708) { + unset_config('book_tocwidth'); + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061708, 'book'); + } + + if ($oldversion < 2012061709) { + require_once("$CFG->dirroot/mod/book/db/upgradelib.php"); + + mod_book_migrate_all_areas(); + + upgrade_mod_savepoint(true, 2012061709, 'book'); + } + + if ($oldversion < 2012061710) { + + // Define field revision to be added to book + $table = new xmldb_table('book'); + $field = new xmldb_field('revision', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'customtitles'); + + // Conditionally launch add field revision + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // book savepoint reached + upgrade_mod_savepoint(true, 2012061710, 'book'); + } + // End of MDL-35297 "replayed" steps. return true; } diff --git a/mod/book/db/upgradelib.php b/mod/book/db/upgradelib.php new file mode 100644 index 00000000000..5411930443c --- /dev/null +++ b/mod/book/db/upgradelib.php @@ -0,0 +1,168 @@ +. + +/** + * Book module upgrade related helper functions + * + * @package mod_book + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * Migrate book files stored in moddata folders. + * + * Please note it was a big mistake to store the files there in the first place! + * + * @param stdClass $book + * @param stdClass $context + * @param string $path + * @return void + */ +function mod_book_migrate_moddata_dir_to_legacy($book, $context, $path) { + global $OUTPUT, $CFG; + + $base = "$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id"; + $fulldir = $base.$path; + + if (!is_dir($fulldir)) { + // does not exist + return; + } + + $fs = get_file_storage(); + $items = new DirectoryIterator($fulldir); + + foreach ($items as $item) { + if ($item->isDot()) { + unset($item); // release file handle + continue; + } + + if ($item->isLink()) { + // do not follow symlinks - they were never supported in moddata, sorry + unset($item); // release file handle + continue; + } + + if ($item->isFile()) { + if (!$item->isReadable()) { + echo $OUTPUT->notification(" File not readable, skipping: ".$fulldir.$item->getFilename()); + unset($item); // release file handle + continue; + } + + $filepath = clean_param("/$CFG->moddata/book/$book->id".$path, PARAM_PATH); + $filename = clean_param($item->getFilename(), PARAM_FILE); + + if ($filename === '') { + // unsupported chars, sorry + unset($item); // release file handle + continue; + } + + if (textlib::strlen($filepath) > 255) { + echo $OUTPUT->notification(" File path longer than 255 chars, skipping: ".$fulldir.$item->getFilename()); + unset($item); // release file handle + continue; + } + + if (!$fs->file_exists($context->id, 'course', 'legacy', '0', $filepath, $filename)) { + $file_record = array('contextid'=>$context->id, 'component'=>'course', 'filearea'=>'legacy', 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename, + 'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime()); + $fs->create_file_from_pathname($file_record, $fulldir.$item->getFilename()); + } + $oldpathname = $fulldir.$item->getFilename(); + unset($item); // release file handle + @unlink($oldpathname); + + } else { + // migrate recursively all subdirectories + $oldpathname = $base.$item->getFilename().'/'; + $subpath = $path.$item->getFilename().'/'; + unset($item); // release file handle + mod_book_migrate_moddata_dir_to_legacy($book, $context, $subpath); + @rmdir($oldpathname); // deletes dir if empty + } + } + unset($items); // release file handles +} + +/** + * Migrate legacy files in intro and chapters + * @return void + */ +function mod_book_migrate_all_areas() { + global $DB; + + $rsbooks = $DB->get_recordset('book'); + foreach($rsbooks as $book) { + upgrade_set_timeout(360); // set up timeout, may also abort execution + $cm = get_coursemodule_from_instance('book', $book->id); + $context = context_module::instance($cm->id); + mod_book_migrate_area($book, 'intro', 'book', $book->course, $context, 'mod_book', 'intro', 0); + + $rschapters = $DB->get_recordset('book_chapters', array('bookid'=>$book->id)); + foreach ($rschapters as $chapter) { + mod_book_migrate_area($chapter, 'content', 'book_chapters', $book->course, $context, 'mod_book', 'chapter', $chapter->id); + } + $rschapters->close(); + } + $rsbooks->close(); +} + +/** + * Migrate one area, this should be probably part of moodle core... + * + * @param stdClass $record object to migrate files (book, chapter) + * @param string $field field in the record we are going to migrate + * @param string $table DB table containing the information to migrate + * @param int $courseid id of the course the book module belongs to + * @param context_module $context context of the book module + * @param string $component component to be used for the migrated files + * @param string $filearea filearea to be used for the migrated files + * @param int $itemid id to be used for the migrated files + * @return void + */ +function mod_book_migrate_area($record, $field, $table, $courseid, $context, $component, $filearea, $itemid) { + global $CFG, $DB; + + $fs = get_file_storage(); + + foreach(array(get_site()->id, $courseid) as $cid) { + $matches = null; + $ooldcontext = context_course::instance($cid); + if (preg_match_all("|$CFG->wwwroot/file.php(\?file=)?/$cid(/[^\s'\"&\?#]+)|", $record->$field, $matches)) { + $file_record = array('contextid'=>$context->id, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid); + foreach ($matches[2] as $i=>$filepath) { + if (!$file = $fs->get_file_by_hash(sha1("/$ooldcontext->id/course/legacy/0".$filepath))) { + continue; + } + try { + if (!$newfile = $fs->get_file_by_hash(sha1("/$context->id/$component/$filearea/$itemid".$filepath))) { + $fs->create_file_from_storedfile($file_record, $file); + } + $record->$field = str_replace($matches[0][$i], '@@PLUGINFILE@@'.$filepath, $record->$field); + } catch (Exception $ex) { + // ignore problems + } + $DB->set_field($table, $field, $record->$field, array('id'=>$record->id)); + } + } + } +} \ No newline at end of file diff --git a/mod/book/version.php b/mod/book/version.php index e187cb33144..f37c00d4531 100644 --- a/mod/book/version.php +++ b/mod/book/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die; $module->component = 'mod_book'; // Full name of the plugin (used for diagnostics) -$module->version = 2012061702; // The current module version (Date: YYYYMMDDXX) +$module->version = 2012061710; // The current module version (Date: YYYYMMDDXX) $module->requires = 2012061700; // Requires this Moodle version $module->cron = 0; // Period for cron to check this module (secs) -- 2.43.0